home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 038a / baswiz17.zip / BASWIZ.DOC < prev    next >
Text File  |  1991-11-06  |  152KB  |  3,342 lines

  1.                           The BASIC Wizard's Library                    page 1
  2.                           =------------------------=
  3.                                   Version 1.7
  4.  
  5.              BasWiz  Copyright (c) 1990-1991  Thomas G. Hanlin III
  6.  
  7.  
  8.  
  9. This software requires the Library Wizard (LIBWIZxx.ZIP) to function.
  10.  
  11. This is BasWiz, a library of assembly language and BASIC routines for use
  12. with QuickBASIC version 4.5.  Full support for QB 4.0-4.5 and BC 6.0-7.1 is
  13. provided with registration (you need to recompile the source code with the
  14. compiler you use).  The BasWiz collection is copyrighted and may be
  15. distributed only if the following conditions are met:
  16.  
  17.    1) No fee of over $10.00 may be charged for distribution.  This
  18.       restriction applies only to physical copies and is not meant to
  19.       prevent distribution by telecommunication services.
  20.  
  21.    2) All BasWiz files must be distributed together in original, unaltered
  22.       form.  See FILES.LST for a list of the 28 BasWiz files included.
  23.  
  24.    3) The library must be distributed as an individual unit.  It may not be
  25.       included as a part of other archives, and no files may be added to it.
  26.       For instance, this means that disk distributors may not distribute
  27.       BasWiz as part of a larger generic unit, and BBS sysops may not add
  28.       advertising files to BasWiz.
  29.  
  30. You use this library at your own risk.  It has been tested by me on my own
  31. computer, but I will not assume any responsibility for any problems which
  32. BasWiz may cause you.  If you do encounter a problem, please let me know
  33. about it, and I will do my best to verify and repair the error.
  34.  
  35. It is expected that if you find BasWiz useful, you will register your copy.
  36. You may not use BasWiz routines in programs intended for sale unless you have
  37. registered.  Registration entitles you to receive the latest version of
  38. BasWiz, complete with full source code in assembly language and BASIC.  The
  39. assembly code is designed for the MASM 6.0 assembler and may require changes
  40. if you wish to use it with OPTASM or TASM.
  41.  
  42. Warning: Use of BasWiz for more than 30 days without registering has been
  43. determined to cause the author to yodel under your window at night!
  44.  
  45. For an example of how to set up your program to access the BasWiz library,
  46. how to LINK the routines, and so forth, take a look at the CREATE.BAT,
  47. GDEMO.BAS and WDEMO.BAS files.  LIBRARY.TXT explains how to use libraries.
  48.  
  49. So who's the BASIC Wizard?  Why, with this library, you will be!  Read this
  50. tome well, for invoking these routines without proper preparation may bring
  51. unexpected results.  Cape and hat (optional) not included.  No assembly
  52. required.
  53.  
  54.                               Table of Contents                         page 2
  55.  
  56.  
  57.  
  58.  Overview and Legal Info ................................................ 1
  59.  
  60.  BCD Math ............................................................... 3
  61.  
  62.  Expression Evaluator ................................................... 6
  63.  
  64.  Extensions to BASIC's math ............................................. 7
  65.  
  66.  Far Strings ............................................................ 9
  67.  
  68.  File Handling ......................................................... 11
  69.  
  70.  Fractions ............................................................. 19
  71.  
  72.  Graphics
  73.     General Routines ................................................... 20
  74.     Text-mode Routines ................................................. 31
  75.     Printer Routines ................................................... 32
  76.     A Little Geometry .................................................. 33
  77.     Equations, Etc ..................................................... 36
  78.  
  79.  Memory Management and Pointers ........................................ 39
  80.  
  81.  Telecommunications .................................................... 42
  82.  
  83.  Virtual Windowing System .............................................. 48
  84.  
  85.  Other Routines ........................................................ 61
  86.  
  87.  Miscellaneous Notes ................................................... 62
  88.  
  89.  Error Codes ........................................................... 65
  90.  
  91.  Troubleshooting ....................................................... 67
  92.  
  93.  History & Philosophy .................................................. 69
  94.  
  95.  Using BasWiz with PDQ ................................................. 71
  96.  
  97.  Credits ............................................................... 72
  98.  
  99.                                    BCD Math                             page 3
  100.  
  101.  
  102.  
  103. Some of you may not have heard of BCD math, or at least not have more than a
  104. passing acquaintance with the subject.  BCD (short for Binary-Coded Decimal)
  105. is a way of encoding numbers.  It differs from the normal method of handling
  106. numbers in several respects.  On the down side, BCD math is much slower than
  107. normal math and the numbers take up more memory.  However, the benefits may
  108. far outweigh these disadvantages, depending on your application: BCD math is
  109. absolutely precise within your desired specifications, and you can make a BCD
  110. number as large as you need.  If your applications don't require great range
  111. or precision out of numbers, normal BASIC math is probably the best choice.
  112. For scientific applications, accounting, engineering and other demanding
  113. tasks, though, BCD may be just the thing you need.
  114.  
  115. The BCD math routines provided by BasWiz allow numbers of up to 255 digits
  116. long (the sign counts as a digit, but the decimal point doesn't).  You may
  117. set the decimal point to any position you like, as long as there is at least
  118. one digit position to the left of the decimal.
  119.  
  120. Since QuickBASIC doesn't support BCD numbers directly, we store the BCD
  121. numbers in strings.  The results are not in text format and won't mean much
  122. if displayed.  A conversion routine allows you to change a BCD number to a
  123. text string in any of a variety of formats.
  124.  
  125. Note that the BCD math handler doesn't yet track overflow/underflow error
  126. conditions.  If you anticipate that this may be a problem, it would be a good
  127. idea to screen your input or to make the BCD range large enough to avoid
  128. these errors.
  129.  
  130. Let's start off by examining the routine which allows you to set the BCD
  131. range:
  132.  
  133.    BCDSetSize LeftDigits%, RightDigits%
  134.  
  135. The parameters specify the maximum number of digits to the left and to the
  136. right of the decimal point.  There must be at least one digit on the left,
  137. and the total number of digits must be less than 255.  The BCD strings will
  138. have a length that's one larger than the total number of digits, to account
  139. for the sign of the number.  The decimal point is implicit and doesn't take
  140. up any extra space.
  141.  
  142. It is assumed that you will only use one size of BCD number in your program--
  143. there are no provisions for handling mixed-length BCD numbers.  Of course,
  144. you could manage that yourself with a little extra work, if it seems like a
  145. useful capability.  If you don't use BCDSetSize, the default size of the BCD
  146. numbers will be 32 (20 to the left, 11 to the right, 1 for the sign).
  147.  
  148. You can get the current size settings in your program, too:
  149.  
  150.    BCDGetSize LeftDigits%, RightDigits%
  151.  
  152.                                    BCD Math                             page 4
  153.  
  154.  
  155.  
  156. Before doing any BCD calculations, you must have some BCD numbers!  The
  157. BCDSet routine takes a number in text string form and converts it to BCD:
  158.  
  159.    TextSt$ = "1234567890.50"
  160.    Nr$ = BCDSet$(TextSt$)
  161.  
  162. If your numbers are stored as actual numbers, you can convert them to a text
  163. string with BASIC's STR$ function, then to BCD.  Leading spaces are ignored:
  164.  
  165.    Nr$ = BCDSet$(STR$(AnyNum#))
  166.  
  167. BCD numbers can also be converted back to text strings, of course.  You may
  168. specify how many digits to the right of the decimal to keep (the number will
  169. be truncated, not rounded).  If the RightDigits% is positive, trailing zeros
  170. will be kept; if negative, trailing zeros will be removed.  There are also
  171. various formatting options which may be used.  Here's how it works:
  172.  
  173.    TextSt$ = BCDFormat$(Nr$, HowToFormat%, RightDigits%)
  174.  
  175. The HowToFormat% value may be any combination of the following (just add the
  176. numbers of the desired formats together):
  177.  
  178.    0   plain number
  179.    1   use commas to separate thousands, etc
  180.    2   start number with a dollar sign
  181.    4   put the sign on the right side instead of the left side
  182.    8   use a plus sign instead of a space if number is not negative
  183.  
  184. The BCD math functions are pretty much self-explanatory, so I'll keep the
  185. descriptions brief.  Here are the single-parameter functions:
  186.  
  187.    Result$ = BCDAbs$(Nr$)              ' get the absolute value of a number
  188.    Result$ = BCDCos$(Nr$)              ' cosine function
  189.    Result$ = BCDCot$(Nr$)              ' cotangent function
  190.    Result$ = BCDCsc$(Nr$)              ' cosecant function
  191.    Result$ = BCDDeg2Rad$(Nr$)          ' convert degrees to radians
  192.    e$ = BCDe$                          ' get the value of the constant "e"
  193.    Result$ = BCDFact$(N%)              ' calculate the factorial of integer N
  194.    Result$ = BCDFrac$(Nr$)             ' return the fractional part of a number
  195.    Result$ = BCDInt$(Nr$)              ' return the integer part of a number
  196.    Result$ = BCDNeg$(Nr$)              ' negate a number
  197.    pi$ = BCDpi$                        ' get the value of the constant "pi"
  198.    Result$ = BCDRad2Deg$(Nr$)          ' convert radians to degrees
  199.    Result$ = BCDSec$(Nr$)              ' secant function
  200.    Result% = BCDSgn%(Nr$)              ' signum function
  201.    Result$ = BCDSin$(Nr$)              ' sine function
  202.    Result$ = BCDSqr$(Nr$)              ' get the square root of a number
  203.    Result$ = BCDTan$(Nr$)              ' tangent function
  204.  
  205.                                    BCD Math                             page 5
  206.  
  207.  
  208.  
  209. Notes on the single-parameter functions:
  210.  
  211.   The signum function returns an integer based on the sign of the BCD number:
  212.      -1   if the BCD number is negative
  213.       0   if the BCD number is zero
  214.       1   if the BCD number is positive
  215.  
  216.   BCDpi$ is accurate to the maximum level afforded by the BCD functions.
  217.   BCDe$ is accurate to as many as 115 decimal places.  The actual accuracy,
  218.   of course, depends on the size of BCD numbers you've chosen.
  219.  
  220.   The trigonometric functions (cos, sin, tan, sec, csc, cot) expect angles in
  221.   radians.  BCDDeg2Rad and BCDRad2Deg will allow you to convert back and
  222.   forth between radians and degrees.
  223.  
  224.  
  225.  
  226. Here is a list of the two-parameter functions:
  227.  
  228.    Result$ = BCDAdd$(Nr1$, Nr2$)      ' add two numbers together
  229.  
  230.    Result$ = BCDSub$(Nr1$, Nr2$)      ' subtract the second nr from the first
  231.  
  232.    Result$ = BCDMul$(Nr1$, Nr2$)      ' multiply one number by another
  233.  
  234.    Result$ = BCDDiv$(Nr1$, Nr2$)      ' divide the first number by the second
  235.  
  236.    Result$ = BCDPower$(Nr$, Power%)   ' raise a number to a power
  237.  
  238.    Result% = BCDCompare%(Nr1$, Nr2$)  ' compare two numbers
  239.  
  240. The comparison function returns an integer which reflects how the two numbers
  241. compare to eachother:
  242.  
  243.    -1   Nr1 < Nr2
  244.     0   Nr1 = Nr2
  245.     1   Nr1 > Nr2
  246.  
  247.                              Expression Evaluator                       page 6
  248.  
  249.  
  250.  
  251. The expression evaluator allows you to find the result of an expression
  252. contained in a string.  Normal algebraic precedence is used, e.g. 4+3*5
  253. evaluates to 19.  The usual numeric operators (*, /, +, -, ^) are supported
  254. (multiply, divide, add, subtract, and raise to a power).  Use of negative
  255. numbers is just fine, of course.  Parentheses for overriding the default
  256. order of operations are also supported.
  257.  
  258. You may use either double asterisk ("**") or a caret ("^") symbols to
  259. indicate exponentiation.
  260.  
  261. To evaluate an expression, you pass it to the evaluator as a string.  You
  262. will get back either an error code or a single-precision result.  Try this
  263. example to see how the expression evaluator works:
  264.  
  265.    REM $INCLUDE: 'BASWIZ.BI'
  266.    DEFINT A-Z
  267.    DO
  268.       INPUT "Expression? "; Expr$
  269.       IF LEN(Expr$) THEN
  270.          Evaluate Expr$, Result!, ErrCode
  271.          IF ErrCode THEN
  272.             PRINT "Invalid expression.  Error code = "; ErrCode
  273.          ELSE
  274.             PRINT "Result: "; Result!
  275.          END IF
  276.       END IF
  277.    LOOP WHILE LEN(Expr$)
  278.    END
  279.  
  280. An expression evaluator adds convenience to any program that needs to accept
  281. numbers.  Why make someone reach for a calculator when number crunching is
  282. what a computer does best?
  283.  
  284.                           Extensions to BASIC's math                    page 7
  285.  
  286.  
  287.  
  288. For the most part, the math routines in this library is designed to provide
  289. alternatives to the math routines that are built into BASIC.  Still, BASIC's
  290. own math support is quite adequate for many purposes, so there's no sense in
  291. ignoring it.  Here are some functions which improve on BASIC's math.
  292.  
  293.    Result! = ArcCosHS!(Nr!)    ' inverse hyperbolic cosine
  294.    Result! = ArcSinHS!(Nr!)    ' inverse hyperbolic sine
  295.    Result! = ArcTanHS!(Nr!)    ' inverse hyperbolic tangent
  296.    Result! = ArcCosS!(Nr!)     ' arc cosine     (1 >= Nr >= -1)
  297.    Result! = ArcSinS!(Nr!)     ' arc sine       (1 >= Nr >= -1)
  298.    Result! = ErfS!(Nr!)        ' error function
  299.    Result! = FactS!(Nr%)       ' factorial
  300.    Result! = CotS!(Nr!)        ' cotangent
  301.    Result! = CscS!(Nr!)        ' cosecant
  302.    Result! = SecS!(Nr!)        ' secant
  303.    Result! = CosHS!(Nr!)       ' hyperbolic cosine
  304.    Result! = SinHS!(Nr!)       ' hyperbolic sine
  305.    Result! = TanHS!(Nr!)       ' hyperbolic tangent
  306.    Result! = Deg2RadS!(Nr!)    ' convert degrees to radians
  307.    Result! = Rad2DegS!(Nr!)    ' convert radians to degrees
  308.    Result! = Cent2Fahr!(Nr!)   ' convert centigrade to Fahrenheit
  309.    Result! = Fahr2Cent!(Nr!)   ' convert Fahrenheit to centigrade
  310.    Result! = Kg2Pound!(Nr!)    ' convert kilograms to pounds
  311.    Result! = Pound2Kg!(Nr!)    ' convert pounds to kilograms
  312.    Pi! = PiS!                  ' the constant "pi"
  313.    e! = eS!                    ' the constant "e"
  314.  
  315.    Result# = ArcCosHD#(Nr#)    ' inverse hyperbolic cosine
  316.    Result# = ArcSinHD#(Nr#)    ' inverse hyperbolic sine
  317.    Result# = ArcTanHD#(Nr#)    ' inverse hyperbolic tangent
  318.    Result# = ArcCosD#(Nr#)     ' arc cosine     (1 >= Nr >= -1)
  319.    Result# = ArcSinD#(Nr#)     ' arc sine       (1 >= Nr >= -1)
  320.    Result# = ErfD#(Nr#)        ' error function
  321.    Result# = FactD#(Nr%)       ' factorial
  322.    Result# = CotD#(Nr#)        ' cotangent
  323.    Result# = CscD#(Nr#)        ' cosecant
  324.    Result# = SecD#(Nr#)        ' secant
  325.    Result# = CosHD#(Nr#)       ' hyperbolic cosine
  326.    Result# = SinHD#(Nr#)       ' hyperbolic sine
  327.    Result# = TanHD#(Nr#)       ' hyperbolic tangent
  328.    Result# = Deg2RadD#(Nr#)    ' convert degrees to radians
  329.    Result# = Rad2DegD#(Nr#)    ' convert radians to degrees
  330.    Pi# = PiD#                  ' the constant "pi"
  331.    e# = eD#                    ' the constant "e"
  332.  
  333.                           Extensions to BASIC's math                    page 8
  334.  
  335.  
  336.  
  337.    Result% = GCDI%(Nr1%, Nr2%) ' greatest common denominator
  338.    Result% = Power2I%(Nr%)     ' raise 2 to a specified power
  339.  
  340.    Result& = GCDL&(Nr1&, Nr2&) ' greatest common denominator
  341.    Result& = Power2L&(Nr%)     ' raise 2 to a specified power
  342.  
  343.  
  344.  
  345. Like BASIC's trig functions, these trig functions expect the angle to be in
  346. radians.  Conversion functions are provided in case you prefer degrees.
  347.  
  348. Note that there is no ArcTanS! or ArcTanD! function for the simple reason
  349. that BASIC supplies an ATN function.
  350.  
  351. Constants are expressed to the maximum precision available.
  352.  
  353. The Power2I% and Power2L& functions are vastly quicker than the equivalent
  354. BASIC formulas.  If powers of two are useful to you, try these functions!
  355.  
  356.  
  357.  
  358. If you are not familiar with variable postfix symbols, here's a brief summary:
  359.  
  360.   Symbol   Meaning             Range (very approximate)
  361.   ------   --------            ------------------------
  362.     %      integer             +- 32767
  363.     &      long integer        +- 2 * 10^9
  364.     !      single precision    +- 1 * 10^38   (7-digit precision float. point)
  365.     #      double precision    +- 1 * 10^308  (15-digit precision float. point)
  366.     $      string              [0 to 32767 characters]
  367.  
  368. See your BASIC manual or QuickBASIC's online help for further details.
  369.  
  370.                                  Far Strings                            page 9
  371.  
  372.  
  373.  
  374. One of the best things about BASIC is its support for variable-length
  375. strings.  Few other languages support such dynamically-allocated strings and
  376. they're a terrifically efficient way of using memory.  At least, they would
  377. be, except for one minor limitation... in every version of QuickBASIC and
  378. BASCOM (except for the new and expensive BASCOM 7.0 "Professional Development
  379. System"), string space is limited to a mere 50K-60K bytes.  As if this
  380. weren't trouble enough, this space is also shared with a number of other
  381. things.  Running out of string space is a common and painful problem.
  382.  
  383. Anyway, it used to be.  The BasWiz library comes with an assortment of
  384. routines and functions which allow you to keep variable-length strings
  385. outside of BASIC's tiny string area.  Currently, you may have up to 65,535
  386. far strings of up to 255 characters each, subject to available memory.
  387. Either normal system memory or expanded memory may be used.  Extended memory
  388. can also be used if you have an XMS driver (such as HIMEM.SYS) installed.
  389.  
  390. Using far strings works almost the same way as using normal strings.  Rather
  391. than referring to a far string with a string variable name, however, you
  392. refer to it with an integer variable called a "handle".  To create a new far
  393. string, you use a handle of zero.  A new handle will be returned to you which
  394. will identify that string for future reference.
  395.  
  396. Before you use any far strings, you must initialize the far string handler.
  397. When you are done using far strings, you must terminate the far string
  398. handler.  Normally, each of these actions will take place only once in your
  399. program: you initialize at the beginning and terminate at the end.
  400.  
  401. On the next page is an example program that reads a file into an array of far
  402. strings, then displays it.  I'll leave out such niceties as error trapping to
  403. keep the example easy to follow.
  404.  
  405. NOTE: The BasWiz far string handler does not support PDS far strings!  If you
  406. are using PDS far strings, you can't use BasWiz far strings.
  407.  
  408.                                  Far Strings                           page 10
  409.  
  410.  
  411.  
  412.    REM $INCLUDE: 'BASWIZ.BI'
  413.    DEFINT A-Z
  414.    REDIM Text(1 TO 5000)                   ' array for far string handles
  415.    FSInit 0                                ' initialize far string handler
  416.    TextLines = 0
  417.    OPEN "ANYFILE.TXT" FOR INPUT AS #1
  418.    DO UNTIL EOF(1)
  419.       LINE INPUT#1, TextRow$
  420.       Handle = 0                           ' use zero to create new far string
  421.       FSSet Handle, TextRow$               ' set the far string
  422.       TextLines = TextLines + 1
  423.       Text(TextLines) = Handle             ' save the far string handle
  424.    LOOP
  425.    CLOSE
  426.    FOR Row = 1 TO TextLines
  427.       PRINT FSGet$(Text(Row))              ' display a far string
  428.    NEXT
  429.    FSDone                                  ' terminate far string handler
  430.    END
  431.  
  432. If you wanted to change an existing far string, you would specify its
  433. existing handle for FSSet.  The handle of zero is used only to create new far
  434. strings, rather in the manner of using a new variable for the first time.
  435.  
  436. Note the 0 after the FSInit call.  That specifies that main system memory
  437. is to be used.  If you would prefer to use EMS, use a 1.  If you specify EMS
  438. and none is available, BasWiz will fall back to conventional memory.
  439.  
  440. I had intended to add XMS support, but on closer inspection, it appears that
  441. this would be quite slow.  Let me know how you feel about this, people!
  442.  
  443.                                 File Handling                          page 11
  444.  
  445.  
  446.  
  447. The file handling capabilities of BASIC were improved considerably as of
  448. QuickBASIC 4.0.  A binary mode was added and it became possible to use
  449. structured (TYPE) variables instead of the awkward FIELD-based random access
  450. handling.  Even today, however, BASIC file handling is inefficient for many
  451. tasks.  It requires error trapping to avoid problems like open floppy drive
  452. doors and cannot transfer information in large quantities at a time.
  453.  
  454. The BasWiz routines provide additional flexibility and power.  They allow you
  455. to access files at as low or high a level as you wish.  Here are some of the
  456. features of BasWiz file handling:
  457.  
  458.   - File sharing is automatically used if the DOS version is high enough,
  459.     (DOS 3.0 or later) providing effortless network compatibility.
  460.   - Critical errors, like other errors, are detected at any point you find
  461.     convenient via a single function call.
  462.   - Optional input buffers speed up reading from files.
  463.   - Up to 32K of data may be read or written at one time.
  464.   - Files can be flushed to disk to avoid loss due to power outages, etc.
  465.  
  466. Files are not considered to be strongly moded by BasWiz, although there are a
  467. few limitations on how you can deal with text files as opposed to other kinds
  468. of files.  Reads and writes normally take place sequentially, like the INPUT
  469. and OUTPUT modes allowed by BASIC.  However, you can also do random access by
  470. moving the file pointer to anywhere in the file, just as with the RANDOM and
  471. BINARY modes allowed by BASIC.  These routines place no arbitrary limitations
  472. on the programmer.
  473.  
  474. As with BASIC, files are referred to by a number after they are opened for
  475. access.  Unlike BASIC, the number is returned to you when the file is
  476. successfully opened, rather than being specified by you when you open the
  477. file.  This means that you never have to worry about a file number already
  478. being in use.  We'll refer to the file number as a "file handle" from now on.
  479.  
  480.                                 File Handling                          page 12
  481.  
  482.  
  483.  
  484. Before doing anything else, you must initialize the file handling routines.
  485. This is typically done only once, at the beginning of your program.  The
  486. FInit routine needs to know the number of files you want to deal with.  This
  487. can be up to 15 files, or possibly up to 50 if you are using DOS 3.3 or
  488. higher.  Support for over 15 files has not been tested, since I don't have
  489. DOS 3.3 or higher, so you use that feature at your own risk!  A future
  490. version of BasWiz will support over 15 open files for DOS 3.0 and above.
  491.  
  492.    FInit Files, ErrCode
  493.  
  494. A file is opened for access like so:
  495.  
  496.    FOpen File$, FMode$, BufferLen, Handle, ErrCode
  497.  
  498. You pass the File$, FMode$, and BufferLen.  The Handle and ErrCode are
  499. returned to you.  The "BufferLen" is the length of the buffer desired for
  500. input.  This must be zero if you want to write to the file.  The filename is
  501. passed in File$, naturally enough.  There is a choice of various modes for
  502. FMode$ and these can be combined to some extent:
  503.  
  504.    A   Append to file      used to add more information to an existing file
  505.    C   Create file         creates a new file
  506.    R   Read access         allows reading (input) from a file
  507.    T   Text mode file      allows text-mode input from a file
  508.    W   Write access        allows writing (output) to a file
  509.  
  510. For the most part, the combinations are self-explanatory.  For instance, it
  511. would be reasonable to open a file for read and write, for create and write,
  512. for append and write, or for read and text.  Text files always require a
  513. buffer.  If you request text access without specifying a buffer, a buffer of
  514. 512 bytes will be provided for you.  If you request create access without
  515. additional parameters, the file will be opened for write by default.
  516.  
  517. You may not use a buffer if you want to write to a file.  This includes text
  518. files, which always use a buffer, as well as binary files.  This is an
  519. artificial limitation which will change in a future version of BasWiz.  It
  520. exists now to reduce the internal complexity of the routines which write to
  521. the file, so that they do not have to account for any buffering as well as
  522. the current file pointer.  However, writing may be done to a text-type file
  523. if the file was not opened in text mode.  We'll see how that works presently.
  524.  
  525. When you are done using a particular file, you can close it, just as in
  526. ordinary BASIC:
  527.  
  528.    FClose Handle
  529.  
  530. Before your program ends, you should terminate the file handler.  This will
  531. close any open files as well as concluding use of the file routines:
  532.  
  533.    FDone
  534.  
  535.                                 File Handling                          page 13
  536.  
  537.  
  538.  
  539. That covers the basic set-up routines: initialize, open, close, and
  540. terminate.  Of more interest are the routines which actually deal with the
  541. file itself.  These provide assorted read/write services, the ability to get
  542. or set the file read/write pointer, size, time, and date, and the ability to
  543. get or set the error code for a specific file, among other things.  Let's
  544. take a look at the error handler first.
  545.  
  546. The FInit and FOpen routines return an error code directly, since you need to
  547. know immediately if these have failed.  The other file routines do not return
  548. a direct error code, however.  In order to discover whether an error has
  549. occurred, you use the FGetError% function.  This will return an error of zero
  550. if there was no error, or a specific error code (listed at the end of this
  551. manual) if some problem occurred.  The error code will remain the same until
  552. you reset it using FError.  The FError service also allows you to test your
  553. error handler by forcing specific error codes even when everything is fine.
  554.  
  555.    PRINT "Error code: "; FGetError(Handle)
  556.    FError Handle, 0                          ' clear the error code
  557.  
  558. It is recommended that you check for errors after any file routine is used if
  559. there is a chance that your program will be executed on a floppy disk.  These
  560. are particularly prone to user errors (like leaving the drive door open) or
  561. running out of space.  If your program will only run on a hard drive, you may
  562. not need to check as frequently.  It's your choice.  Note that the error code
  563. is not cleared automatically-- use FError to reset the error code to zero if
  564. you determine that it wasn't a "fatal" error.
  565.  
  566. Down to the nitty-gritty... we've seen how to open and close a file, how to
  567. check operations for errors, and so forth.  So how do we actually manipulate
  568. the file?  There are assorted alternatives, depending on how you want to deal
  569. with the file: text reads, text writes, byte-oriented reads and writes, and
  570. block reads and writes, not to mention handling the time, date, size, and
  571. read/write pointer.  We'll start off with the routines which read from a
  572. file.
  573.  
  574. If you opened the file for text access, you must want to read the file a line
  575. at a time.  Each line is assumed to be less than 256 characters and delimited
  576. by a carriage return and linefeed (<CR><LF>, or ^M^J, in normal notation).
  577. In that case, you should use the FReadLn$ function:
  578.  
  579.    St$ = FReadLn$(Handle)
  580.  
  581. A simple program to display a text file directly on the screen might look
  582. something like this in BASIC:
  583.  
  584.    OPEN COMMAND$ FOR INPUT AS #1
  585.    WHILE NOT EOF(1)
  586.       LINE INPUT#1, St$
  587.       PRINT St$
  588.    WEND
  589.    CLOSE #1
  590.  
  591.                                 File Handling                          page 14
  592.  
  593.  
  594.  
  595. The same program using BasWiz would look something like this:
  596.  
  597.    REM $INCLUDE: 'BASWIZ.BI'
  598.    DEFINT A-Z
  599.    FInit 15, ErrCode
  600.    FOpen COMMAND$, "RT", 0, Handle, ErrCode
  601.    WHILE NOT FEOF(Handle)
  602.       PRINT FReadLn$(Handle)
  603.    WEND
  604.    FDone
  605.  
  606. In either case, we're accepting a command-line parameter which specifies the
  607. name of the file.  In the BasWiz example, note the use of the FEOF% function,
  608. which tells whether we've gone past the end of the file.  This works like the
  609. EOF function in BASIC.
  610.  
  611. There are two ways of reading from binary files.  You can get the results as
  612. a string of a specified (maximum) length:
  613.  
  614.    St$ = FRead$(Handle, Bytes)
  615.  
  616. In plain BASIC, the same thing might be expressed this way:
  617.  
  618.    St$ = INPUT$(Bytes, FileNumber)
  619.  
  620. The other way of reading from a binary file has no equivalent in BASIC.  It
  621. allows you to read in up to 32K bytes at a time, directly into an array or
  622. TYPEd variable.  You can read the information into anything that doesn't
  623. contain normal strings (the fixed-length string type can be used, though):
  624.  
  625.    Segm = VARSEG(Array(0))
  626.    Offs = VARPTR(Array(0))
  627.    FBlockRead Handle, Segm, Offs, Bytes
  628.  
  629. That would read the specified number of bytes into Array(), starting at array
  630. element zero.  You can use any data type, whether single variable or array,
  631. as long as it is not a variable length string.  In other words, Vbl$ and
  632. Vbl$(0) would not work.  If you want to use a string with the block read, it
  633. must be a fixed-length string.  For example:
  634.  
  635.    DIM Vbl AS STRING * 1024
  636.    Segm = VARSEG(Vbl)
  637.    Offs = VARPTR(Vbl)
  638.    FBlockRead Handle, Segm, Offs, Bytes
  639.  
  640. It's a good idea to calculate the Segm and Offs values each time.  These tell
  641. FBlockRead where to store the information it reads.  QuickBASIC may move the
  642. variable around in memory, so VARSEG and VARPTR should be used just before
  643. FBlockRead, to insure that they return current and correct information.
  644.  
  645.                                 File Handling                          page 15
  646.  
  647.  
  648.  
  649. The file output commands are similar.  File output can only be done if there
  650. is no input buffer.  This means that you can't use file output if the file
  651. was opened in text mode, either, since text mode always requires an input
  652. buffer.  That's a limitation that will be removed in a future version of
  653. BasWiz.  It is possible to do text output on a file that was opened in binary
  654. mode, however.  The limitation just means that you can't open a file for both
  655. reading and writing if you use a buffer (or text mode).
  656.  
  657. To output (write) a string to a file, use this:
  658.  
  659.    FWrite Handle, St$
  660.  
  661. This is like the plain BASIC statement:
  662.  
  663.    PRINT #FileNumber, St$;
  664.  
  665. If you would like the string to be terminated by a carriage return and
  666. linefeed, use this instead:
  667.  
  668.    FWriteLn Handle, St$
  669.  
  670. This is like the plain BASIC statement:
  671.  
  672.    PRINT #FileNumber, St$
  673.  
  674. In BASIC, the difference between the two writes is controlled by whether you
  675. put a semicolon at the end.  With BasWiz, different routines are used
  676. instead.  FWrite is like PRINT with a semicolon and FWriteLn is like PRINT
  677. without a semicolon.
  678.  
  679. As well as simple string output, you can also output TYPEd variables and
  680. even entire arrays.  This type of output has no corresponding BASIC
  681. instruction, although it's somewhat similar to the file PUT statement.  Up to
  682. 32K can be output at a time:
  683.  
  684.    Segm = VARSEG(Array(0))
  685.    Offs = VARPTR(Array(0))
  686.    FBlockWrite Handle, Segm, Offs, Bytes
  687.  
  688. If you haven't already read the section on FBlockRead, go back a page and
  689. review it.  The same comments apply for FBlockRead: it can handle
  690. fixed-length strings but not old-style strings, and VARSEG/VARPTR should
  691. immediately precede the block I/O, among other things.
  692.  
  693.                                 File Handling                          page 16
  694.  
  695.  
  696.  
  697. Normally, reads and writes take place sequentially.  If you want to move to a
  698. specific spot in the file, though, that's easy.  You can do it in text mode
  699. or binary mode, whether or not you have a buffer, giving you additional
  700. flexibility over the usual BASIC file handling.  Set the location for the
  701. next read or write like so:
  702.  
  703.    FLocate Handle, Position&
  704.  
  705. The Position& specified will be where the next read or write takes place.  It
  706. starts at one and (since it's specified as a LONG integer) can go up to
  707. however many bytes are in the file.  If you want a record position rather
  708. than a byte position, you can do that too.  Just convert the record number to
  709. a byte number, like so:
  710.  
  711.    Position& = (RecordNumber& - 1&) * RecordLength& + 1&
  712.  
  713. If you do not want to maintain RecordNumber and RecordLength as LONG
  714. integers, convert them to such by using the CLNG() function on them before
  715. doing the calculation.  Otherwise you may get an overflow error in the
  716. calculation, since QuickBASIC will assume that the result will be an integer.
  717.  
  718. You can get the current position of the file read/write pointer too:
  719.  
  720.    Position& = FGetLocate&(Handle)
  721.  
  722. Let's see... we've examined initialization and termination, opening and
  723. closing, reading and writing, and manipulating the file read/write pointer.
  724. What else could there be?  Well, how about checking the size of a file and
  725. getting or setting the file time and date?  Why, sure!  The "get" routines
  726. are pretty well self-explanatory:
  727.  
  728.    FileSize& = FGetSize&(Handle)
  729.    FileTime$ = FGetTime$(Handle)
  730.    FileDate$ = FGetDate$(Handle)
  731.  
  732. Setting the time and date is equally easy.  This should be done just before
  733. you close the file with FClose or FDone.  You may use any date and time
  734. delimiters you choose.  If a field is left blank, the appropriate value from
  735. the current time or date will be used.  Years may be specified in four-digit
  736. or two-digit format.  Two-digit years will be assumed to be in the 20th
  737. century ("90" == "1990").  Careful there!  Your program should allow
  738. four-digit dates to be used or disaster will strike when the year 2000
  739. rolls around.  The 21st century is closer than you think!
  740.  
  741.    FTime Handle, FileTime$
  742.    FDate Handle, FileDate$
  743.  
  744.                                 File Handling                          page 17
  745.  
  746.  
  747.  
  748. There's just one more file routine.  It allows you to "flush" a file to disk.
  749. This insures that the file has been properly updated to the current point, so
  750. nothing will be lost if there is a power outage or similar problem.  If you
  751. do not use the "flush" routine, data may be lost if the program terminates
  752. unexpectedly (without going through FClose or FDone).  Note that use of
  753. FFlush requires that a free file handle be available, under most DOS versions.
  754.  
  755.    FFlush Handle
  756.  
  757. That's it for the BasWiz file handler.  As a quick review, let's run through
  758. the available routines, then try a couple of example programs.  Remember that
  759. the BasWiz.REF file contains a brief reference for all of these routines too!
  760. You might also wish to examine the WDEMO.BAS program, which also makes use of
  761. the file routines.
  762.  
  763. FInit         initialize the file handler
  764. FDone         terminate the file handler and close any open files
  765.  
  766. FOpen         open a file for access (like OPEN)
  767. FClose        close a file (like CLOSE)
  768.  
  769. FRead$        read a string from a binary file (like INPUT$)
  770. FReadLn$      read a string from a text file (like LINE INPUT)
  771. FBlockRead    read an item (TYPE, STRING*##, or array) from a binary file
  772.  
  773. FWrite        write a string to a binary file
  774. FWriteLn      write a string with a <CR><LF> to a binary file
  775. FBlockWrite   write an item (TYPE, STRING*##, or array) to a binary file
  776.  
  777. FLocate       set the read/write pointer to a specified position
  778. FTime         set the time stamp
  779. FDate         set the date stamp
  780. FError        set the error code
  781.  
  782. FGetLocate&   get the read/write pointer
  783. FGetTime$     get the time stamp
  784. FGetDate$     get the date stamp
  785. FGetError     get the error code
  786.  
  787. FFlush        flush to disk (makes sure file is updated and current)
  788. FGetSize&     get size
  789. FEOF          determine whether the end of the file has been reached
  790.  
  791.                                 File Handling                          page 18
  792.  
  793.  
  794.  
  795. So much for theory.  Let's try something practical.  A common problem is
  796. copying one file to another.  We'll limit this to text files, so we can do it
  797. in both plain BASIC and with BasWiz.  Although BasWiz can handle any type of
  798. file readily, BASIC has problems in efficiently handling variable-length
  799. binary files.  So, we'll do this first in BASIC, then BasWiz, for text files.
  800.  
  801. In BASIC, a text-file copying program might look like this:
  802.  
  803.    INPUT "File to copy"; FromFile$
  804.    INPUT "Copy file to"; ToFile$
  805.    OPEN FromFile$ FOR INPUT AS #1
  806.    OPEN ToFile$ FOR OUTPUT AS #2
  807.    WHILE NOT EOF(1)
  808.       LINE INPUT#1, St$
  809.       PRINT#2, St$
  810.    WEND
  811.    CLOSE
  812.  
  813. With BasWiz, the same program would look more like this:
  814.  
  815.    REM $INCLUDE: 'BASWIZ.BI'
  816.    DEFINT A-Z
  817.    INPUT "File to copy"; FromFile$
  818.    INPUT "Copy file to"; ToFile$
  819.    FInit 15, ErrCode
  820.    FOpen FromFile$, "RT", 1024, FromHandle, ErrCode
  821.    FOpen ToFile$, "CW", 0, ToHandle, ErrCode
  822.    FileTime$ = FGetTime$(FromHandle)
  823.    FileDate$ = FGetDate$(FromHandle)
  824.    WHILE NOT FEOF(FromHandle)
  825.       WriteLn ToHandle, ReadLn$(FromHandle)
  826.    WEND
  827.    FTime ToHandle, FileTime$
  828.    FDate ToHandle, FileDate$
  829.    FDone
  830.  
  831. You might have noticed that the BasWiz version of the program is a bit longer
  832. than the plain BASIC version.  It has a number of advantages, however.  It's
  833. faster, produces smaller code under ordinary circumstances, and preserves the
  834. date and time of the original file in the copied file.  Unlike BASIC, the
  835. BasWiz routines do not automatically add a ^Z to the end of text files, so
  836. the BasWiz example will not alter the original file.
  837.  
  838.                                   Fractions                            page 19
  839.  
  840.  
  841.  
  842. Using BCD allows you to represent numbers with excellent precision, but at a
  843. fairly large cost in speed.  Another way to represent numbers with good
  844. precision is to use fractions.  Fractions can represent numbers far more
  845. accurately than BCD, but can be handled much more quickly.  There are some
  846. limitations, of course, but by now you've guessed that's always true!
  847.  
  848. Each fraction is represented by BasWiz as an 8-byte string.  The numerator
  849. (top part of the fraction) may be anywhere from -999,999,999 to 999,999,999.
  850. The denominator (the bottom part) may be from 1 to 999,999,999.  This allows
  851. handling a fairly wide range of numbers exactly.
  852.  
  853. Fractions can be converted to or from numeric text strings in any of three
  854. formats: real number (e.g., "1.5"), plain fraction (e.g., "3/2"), or whole
  855. number and fraction (e.g., "1 1/2").  Internally, the numbers are stored as a
  856. plain fraction, reduced to the smallest fraction possible which means the
  857. same thing (for instance, "5/10" will be reduced to "1/2").
  858.  
  859. To convert a numeric text string into a fraction, do this:
  860.  
  861.    Nr$ = FracSet$(NumSt$)
  862.  
  863. To convert a fraction into a numeric text string, try this:
  864.  
  865.    NumSt$ = FracFormat$(Nr$, HowToFormat%)
  866.  
  867. The formatting options are:
  868.  
  869.    0   convert to plain fraction
  870.    1   convert to whole number and fraction
  871.    2   convert to decimal number
  872.  
  873. Here is a list of the other functions available:
  874.  
  875.    Result$ = FracAbs$(Nr$)            ' take the absolute value of a fraction
  876.    Result$ = FracAdd$(Nr1$, Nr2$)     ' add two fractions
  877.    Result% = FracCompare%(Nr1$, Nr2$) ' compare two fractions
  878.    Result$ = FracDiv$(Nr1$, Nr2$)     ' divide the first fraction by the second
  879.    Result$ = FracMul$(Nr1$, Nr2$)     ' multiply two fractions
  880.    Result$ = FracNeg$(Nr$)            ' negate a fraction
  881.    Result% = FracSgn%(Nr$)            ' signum function for a fraction
  882.    Result$ = FracSub$(Nr1$, Nr2$)     ' subtract the 2nd fraction from the 1st
  883.  
  884. Fractions are automatically reduced to allow the greatest possible range.
  885. Note that little range-checking is done at this point, so you may wish to
  886. screen any input to keep it reasonable.
  887.  
  888.    Result     FracSgn      FracCompare
  889.      -1       negative #    1st < 2nd
  890.       0       # is zero     1st = 2nd
  891.       1       positive #    1st > 2nd
  892.  
  893.                          Graphics: General Routines                    page 20
  894.  
  895.  
  896.  
  897. These routines are designed to work with specific graphics modes, so your
  898. program will only include those routines which apply to the modes you use.
  899. The following modes are currently supported:
  900.  
  901.  SCREEN   Card     Graph. Res   Colors   Text Res.         Notes
  902.  ======   ====     ==========   ======   =============     =====
  903.     0      any       varies       16     varies              *0
  904.     1      CGA     320 x 200       4     40 x 25
  905.     2      CGA     640 x 200       2     80 x 25
  906.     3      HGA     720 x 348       2     90 x 43             *1
  907.     7      EGA     320 x 200      16     40 x 25
  908.     8      EGA     640 x 200      16     80 x 25
  909.     9      EGA     640 x 350      16     80 x 25/43
  910.    10      EGA     640 x 350       4     80 x 25/43         mono
  911.    11      VGA     640 x 480       2     80 x 30/60
  912.    12      VGA     640 x 480      16     80 x 30/60
  913.    13      VGA     320 x 200     256     40 x 25
  914.  ----------------------------------------------------------------
  915.    N0      VGA     360 x 480     256     45 x 30             *2
  916.    N1      VGA     320 x 400     256     40 x 25             *2
  917.    N2    <Epson>   480 x 640       2     60 x 80/45/40       *3
  918.    N4      any      80 x  50       2     10 x 6              *4
  919.    N5     SVGA    <user spec>    256     <varies>            *5
  920.  
  921.  
  922. The number of rows of text available depends on the font: 8x8, 8x14, or 8x16.
  923.  
  924. *0  This is actually for text mode, not graphics mode.
  925.  
  926. *1  Note that the BasWiz Hercules routines, unlike those provided with
  927.     QuickBASIC, do not require the QBHERC TSR to be loaded.  They are
  928.     entirely self-contained.  However, they may need to be compiled by BC
  929.     instead of QB, which may refuse to deal with the video mode change.
  930.  
  931. *2  This is a non-standard VGA mode.  It should work on most VGAs, however.
  932.  
  933. *3  This works with an Epson-compatible printer rather than the display.  The
  934.     results may be previewed on a VGA, though.  See also "Printer Routines".
  935.  
  936. *4  This actually provides graphics in text mode.  It will work on any
  937.     display adapter.  80x25 text remains available through PRINT.
  938.  
  939. *5  This mode provides support for high-resolution 256-color SuperVGA modes.
  940.     You must specify the appropriate BIOS mode number and resolution.  Only
  941.     Tseng-based video adapters are supported.
  942.  
  943. See "Miscellaneous Notes" for additional remarks.
  944.  
  945. Compatibility notes:
  946.    An EGA can display CGA modes.
  947.    A VGA can display EGA and CGA modes.
  948.    An MCGA can display CGA modes and two VGA modes: SCREEN 11 and SCREEN 13.
  949.  
  950.                          Graphics: General Routines                    page 21
  951.  
  952.  
  953.  
  954. The routine for a specific mode is indicated by a prefix of "G", followed by
  955. the mode number, and then the routine name.  For example, if you wished to
  956. plot a point in SCREEN 2 mode, you would use:
  957.  
  958.    G2Plot X%, Y%
  959.  
  960. Many of these routines correspond with existing BASIC instructions.  However,
  961. they are smaller and usually faster by 22% - 64%.  See "Miscellaneous Notes"
  962. for notes on the differences between BASIC and the BasWiz routines.
  963.  
  964. The smaller size may not be noticeable if you use the SCREEN statement, since
  965. that causes BASIC to link in some of its own graphics routines.  If you
  966. intend to use only BasWiz routines for graphics, you can avoid that by using
  967. the G#Mode command instead of SCREEN:
  968.  
  969.    G#Mode Graphics%         ' use 0 for SCREEN 0, any other for SCREEN #
  970.  
  971. If you're using the mode N5 routines, you'll need to initialize them before
  972. calling GN5Mode.  This is done by specifying the BIOS mode number and the
  973. screen resolution:
  974.  
  975.    GN5Mode BIOSMode%, PixelsWide%, PixelsHigh%
  976.  
  977. One difference between BASIC and BasWiz is that, instead of each "draw"
  978. command requiring a color parameter as in BASIC, the BasWiz library provides
  979. a separate color command:
  980.  
  981.    G#Color Foreground%, Background%
  982.  
  983. The "foreground" color is used by all graphics routines.  The background
  984. color is used by the G#Cls routine.  Both foreground and background colors
  985. are used in the G#Write and G#WriteLn routines.
  986.  
  987.                          Graphics: General Routines                    page 22
  988.  
  989.  
  990.  
  991. Here is a list of the corresponding routines, first BASIC, then BasWiz
  992. (replace the "#" with the appropriate mode number):
  993.  
  994.    ' get the color of a specified point
  995.    colour% = POINT(x%, y%)
  996.    colour% = G#GetPel(x%, y%)
  997.  
  998.    ' set the color of a specified point
  999.    PSET (x%, y%), colour%
  1000.    G#Color colour%, backgnd% : G#Plot x%, y%
  1001.  
  1002.    ' draw a line of a specified color
  1003.    LINE (x1%, y1%) - (x2%, y2%), colour%
  1004.    G#Color colour%, backgnd% : G#Line x1%, y1%, x2%, y2%
  1005.  
  1006.    ' draw a box frame of a specified color
  1007.    LINE (x1%, y1%) - (x2%, y2%), colour%, B
  1008.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 0
  1009.  
  1010.                          Graphics: General Routines                    page 23
  1011.  
  1012.  
  1013.  
  1014. Here are some more BASIC and BasWiz routines:
  1015.  
  1016.    ' draw a box of a specified color and fill it in
  1017.    LINE (x1%, y1%) - (x2%, y2%), colour%, BF
  1018.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 1
  1019.  
  1020.    ' clear the screen and home the cursor
  1021.    CLS
  1022.    G#Cls
  1023.  
  1024.    ' get the current cursor position
  1025.    Row% = CSRLIN: Column% = POS(0)
  1026.    G#GetLocate Row%, Column%
  1027.  
  1028.    ' set the current cursor position
  1029.    LOCATE Row%, Column%
  1030.    G#Locate Row%, Column%
  1031.  
  1032.    ' display a string without a carriage return and linefeed
  1033.    PRINT St$;
  1034.    G#Write St$
  1035.  
  1036.    ' display a string with a carriage return and linefeed
  1037.    PRINT St$
  1038.    G#WriteLn St$
  1039.  
  1040. Note that BasWiz, unlike BASIC, allows both foreground and background colors
  1041. for text in graphics mode.  It also displays text substantially faster than
  1042. BASIC.  See the "Miscellaneous Notes" section for information on other
  1043. differences in text printing.
  1044.  
  1045. If you need to print a number rather than a string, just use the BASIC
  1046. function STR$ to convert it.  If you don't want a leading space (assuming the
  1047. number is not negative), use this formula:
  1048.  
  1049.    St$ = MID$(STR$(Number), 2)
  1050.  
  1051. The BasWiz library has other routines which have no BASIC equivalent.  One
  1052. allows you to get the current colors:
  1053.  
  1054.    G#GetColor Foreground%, Background%
  1055.  
  1056.                          Graphics: General Routines                    page 24
  1057.  
  1058.  
  1059.  
  1060. Sometimes the normal text services seem unduly limited.  Text is displayed
  1061. only at specific character positions, so it may not align properly with a
  1062. graph, for instance.  Text is also of only one specific size.  These are
  1063. limitations which make the normal text routines very fast, but for times when
  1064. you need something a little bit more fancy, try:
  1065.  
  1066.    G#Banner St$, X%, Y%, Xmul%, Ymul%
  1067.  
  1068. You may display the string starting at any graphics position.  The Xmul% and
  1069. Ymul% values are multipliers, specifying how many times larger than normal
  1070. each character should be.  Using Xmul% = 1 and Ymul% = 1 will give you
  1071. normal-sized characters.  What "normal" means depends on the font in use.
  1072.  
  1073. Since G#Banner "draws" the text onto the screen, it is a bit slower than the
  1074. normal text services.  It also uses only the foreground color, so the letters
  1075. go right on top of anything that was previously there.  Use G#Box to clear
  1076. the area beforehand if this is a problem for you.
  1077.  
  1078. The G#Banner routine supports several fonts.  The larger fonts provide a more
  1079. precise character set but leave you with less room on the screen.  You may
  1080. choose from these fonts:
  1081.  
  1082.    Font Number     Font Size (width x height)
  1083.         0            8 x 8    --- default
  1084.         1            8 x 14
  1085.         2            8 x 16
  1086.  
  1087. Select a font like so:
  1088.  
  1089.    BFont FontNr%
  1090.  
  1091. If you want to find out what the current font is, that's possible too:
  1092.  
  1093.    FontNr% = GetBFont
  1094.  
  1095. Besides looking more elegant, the larger fonts are easier to read.  They will
  1096. also suffer less from being increased in size, although some deterioration is
  1097. inevitable when magnifying these kinds of fonts.
  1098.  
  1099. The G#Banner routines accept CHR$(0) - CHR$(127).  No handling of control
  1100. codes is done.  All codes are displayed directly to the screen.
  1101.  
  1102.                          Graphics: General Routines                    page 25
  1103.  
  1104.  
  1105.  
  1106. Circles and ellipses can be drawn with the Ellipse routine.  This is similar
  1107. to the BASIC CIRCLE statement.  You specify the center of the ellipse (X,Y),
  1108. plus the X and Y radius values:
  1109.  
  1110.    G#Ellipse CenterX%, CenterY%, XRadius%, YRadius%
  1111.  
  1112. A circle is an ellipse with a constant radius.  So, to draw a circle, just
  1113. set both radius values to the single desired radius.
  1114.  
  1115. As well as the usual points, lines, and ellipses, BasWiz also allows you to
  1116. draw polygons: triangles, squares, pentagons, hexagons, all the way up to
  1117. full circles!
  1118.  
  1119.    G#Polygon X%, Y%, Radius%, Vertices%, Angle!
  1120.  
  1121. The X% and Y% values represent the coordinates of the center of the polygon.
  1122. The Radius% is the radius of the polygon (as if you were fitting it into a
  1123. circle).  Vertices% is the number of angles (also the number of sides) for
  1124. the polygon to have.  Angle! specifies the rotation of the polygon, and is
  1125. specified in radians.  See "A Little Geometry" for more information.
  1126.  
  1127. Another routine is designed to manipulate a GET/PUT image.  Given an image in
  1128. array Original%() and a blank array of the same dimensions called Flipped%(),
  1129. this routine copies the original image to the new array as a mirror image
  1130. about the horizontal axis.  This is the same as the image you'd see if you
  1131. turned your monitor upside-down: the resulting image is upside-down and
  1132. backwards.
  1133.  
  1134.    G#MirrorH Original%(), Flipped%()
  1135.  
  1136. Don't forget to make the Flipped%() array the same DIM size as the original,
  1137. or the picture will overflow into main memory, probably causing disaster!
  1138.  
  1139. Note that G#MirrorH will only work properly on images with byte alignment.
  1140. This means that the width of the image must be evenly divisible by four if
  1141. SCREEN 1 is used, or evenly divisible by eight if SCREEN 2 is used.  EGA
  1142. modes are not yet supported for this routine.
  1143.  
  1144.                          Graphics: General Routines                    page 26
  1145.  
  1146.  
  1147.  
  1148. There are more routines that work only with SCREEN 2.  One allows you to load
  1149. a MacPaint-type image ("ReadMac" or .MAC files) into an array which can then
  1150. be PUT onto the screen:
  1151.  
  1152.    G2LoadMAC FileName$, Image%(), StartRow%
  1153.  
  1154. Note that a full .MAC picture is 576x720, which won't fit on the screen, so
  1155. the image will be truncated to 576x200.  You may specify a starting row
  1156. within the .MAC image, StartRow%, which may be 0-521, allowing the entire
  1157. picture to be loaded in several parts.
  1158.  
  1159. The Image%() must be dimensioned with 7202 elements:
  1160.  
  1161.    DIM Array(1 TO 7202) AS INTEGER
  1162.  
  1163. If you don't give an extension in the FileName$, an extension of ".MAC" will
  1164. be used.  There is no checking to see if the file actually exists, so you may
  1165. wish to do this beforehand.
  1166.  
  1167. There is no way of knowing whether a .MAC picture is supposed to be black on
  1168. white or white on black.  If the image doesn't look right when you PUT using
  1169. PSET, you can switch it around by using PUT with PRESET instead.
  1170.  
  1171. PC PaintBrush (.PCX) pictures can also be loaded.  These images can be of
  1172. various sizes, so you need to dimension a dynamic array for them:
  1173.  
  1174.    REM $DYNAMIC
  1175.    DIM Image(1 TO 2) AS INTEGER
  1176.  
  1177. The array will be set to the correct size by the loader.  It goes like this:
  1178.  
  1179.    G2LoadPCX FileName$, Image%(), ErrCode%
  1180.  
  1181. If you don't give an extension in the FileName$, an extension of ".PCX" will
  1182. be used.  You may wish to check to see if the file exists beforehand.
  1183. Possible errors are as follows:
  1184.  
  1185.    -1   File is not in PCX format
  1186.     1   Image is too large for desired screen mode
  1187.     2   Image won't work in desired screen mode (too many planes/colors)
  1188.  
  1189.                          Graphics: General Routines                    page 27
  1190.  
  1191.  
  1192.  
  1193. Two new routines are replacements for the GET and PUT image statements in
  1194. BASIC.  They are on the slow side, but if you don't intend to use them for
  1195. animation, they will serve to save some memory.  There are also GN5Get and
  1196. GN5Put routines for use with 256-color SuperVGA modes.
  1197.  
  1198.    REM $DYNAMIC
  1199.    DIM Image(1 TO 2) AS INTEGER
  1200.    G2Get X1%, Y1%, X2%, Y2%, Image()
  1201.  
  1202. Note the DIMensioning of a dynamic array.  The G2Get routine will set the
  1203. array to the appropriate size to hold the image.
  1204.  
  1205. The PUT replacement assumes that you intend to PSET the image.  It doesn't
  1206. allow for other display modes yet:
  1207.  
  1208.    G2Put X%, Y%, Image()
  1209.  
  1210. See "Miscellaneous Notes" for more information on using GET/PUT images and
  1211. the directions I'll be taking with them in the future.  Note that SCREEN 13
  1212. is also supported, via G13Get and G13Put.
  1213.  
  1214. The COLOR statement in SCREEN 1 is anomalous.  It doesn't really control
  1215. color at all, which is why QuickBASIC proper doesn't support colored text in
  1216. this (or any graphics) mode.  Instead, it is used for controlling the
  1217. background/border color and palette.  Since BasWiz -does- support a true
  1218. G1COLOR routine, there are different routines which allow you to change the
  1219. palette and border colors. To change the background (and border) color, use:
  1220.  
  1221.    G1Border Colour%
  1222.  
  1223.                          Graphics: General Routines                    page 28
  1224.  
  1225.  
  1226.  
  1227. There are two palette routines.  Why two?  Well, QuickBASIC supports two CGA
  1228. palettes.  One of the routines works like QuickBASIC and can be used on any
  1229. CGA, EGA or VGA display (as long as it's in CGA mode).  The other routine
  1230. gives you a wider choice of palettes, but will only work on true CGAs (and
  1231. some EGA or VGA systems that have been "locked" into CGA mode).
  1232.  
  1233. Here's the QuickBASIC-style two-palette routine for any CGA/EGA/VGA:
  1234.  
  1235.    G1PaletteA PaletteNr%
  1236.  
  1237. The PaletteNr% may be as follows:
  1238.  
  1239.    0     (bright) Green, Red, Yellow
  1240.    1     Cyan, Violet, White
  1241.  
  1242.  
  1243. The more flexible six-palette routine (for CGA only) works like this:
  1244.  
  1245.    G1PaletteB PaletteNr%
  1246.  
  1247. Palettes are as follows:
  1248.  
  1249.    0     Green, Red, Brown            4     (bright) Green, Red, Yellow
  1250.    1     Cyan, Violet, White          5     (bright) Cyan, Violet, White
  1251.    2     Cyan, Red, White             6     (bright) Cyan, Red, White
  1252.  
  1253.                          Graphics: General Routines                    page 29
  1254.  
  1255.  
  1256.  
  1257. The EGA has a number of features which work in all its modes, so rather than
  1258. giving them screen mode prefixes, they are simply named with an "E".  These
  1259. routines allow you to get or set the palette, get or set the border color,
  1260. and determine whether the higher background colors should be displayed as
  1261. bright colors or as blinking.
  1262.  
  1263. To get a palette color value, use:
  1264.  
  1265.    Colour% = EGetPalette(ColorNumber%)
  1266.  
  1267. To set the color value, use:
  1268.  
  1269.    EPalette ColorNumber%, Colour%
  1270.  
  1271. To get the border color:
  1272.  
  1273.    Colour% = EGetBorder%
  1274.  
  1275. You can probably guess how to set the border color:
  1276.  
  1277.    EBorder Colour%
  1278.  
  1279. Finally, the blink vs. intensity.  Actually, this is designed for text mode;
  1280. I'm not sure whether it has any function in graphics modes.  The text-mode
  1281. default is for blinking to be turned on.  With BASIC, you add 16 to the
  1282. foreground color to make it blink.  That's a little weird, since the "blink"
  1283. attribute is actually a part of the background color, but that's how BASIC
  1284. views it.  You can tell the EGA to turn off blinking, in which case adding 16
  1285. to the foreground color makes the background color intense.  This doubles the
  1286. number of available background colors.
  1287.  
  1288.    EBlink Blink%
  1289.  
  1290. Use -1 for blinking (default), or 0 to turn off blinking.
  1291.  
  1292.                          Graphics: General Routines                    page 30
  1293.  
  1294.  
  1295.  
  1296. Like the EGA, the VGA has a number of features which work in all its modes.
  1297. Again, rather than giving them screen mode prefixes, we simply name them with
  1298. a "V".  The current routines allow you to get or set the palette colors.
  1299.  
  1300. To get a palette color value, use:
  1301.  
  1302.    VGetPalette(ColorNumber%, Red%, Green%, Blue%)
  1303.  
  1304. To set the color value, use:
  1305.  
  1306.    VPalette ColorNumber%, Red%, Green%, Blue%
  1307.  
  1308. As you've probably noticed, this doesn't work the same way as the QuickBASIC
  1309. PALETTE statement.  Rather than using a formula to calculate a single LONG
  1310. color value, like QuickBASIC, the BasWiz library allows you to specify the
  1311. color in a more meaningful way.  The Red%, Green%, and Blue% parameters each
  1312. hold an intensity value (0-63).  By mixing these three, you can get an
  1313. immense variety of shades-- over 250,000 combinations in all.
  1314.  
  1315. If you need to keep track of the intensities in your program, I'd suggest the
  1316. following TYPE definition:
  1317.  
  1318.    TYPE VGAcolor
  1319.       Red AS INTEGER
  1320.       Green AS INTEGER
  1321.       Blue AS INTEGER
  1322.    END TYPE
  1323.  
  1324. If space is more important than speed, you can compress that to half the size
  1325. by using STRING * 1 instead of INTEGER.  In that case, you will need to use
  1326. the CHR$ and ASC functions to convert between string and integer values.
  1327.  
  1328.                         Graphics: Text-mode Routines                   page 31
  1329.  
  1330.  
  1331.  
  1332. It may seem odd to lump text-mode handling in with graphics mode.  It seemed
  1333. like the most logical approach, however.  There is certainly some value in
  1334. having graphics-type capabilities for text mode.  The ability to draw lines
  1335. and boxes, use banner-style text, and so forth can be handy.  So, for the
  1336. folks who don't need all the power of the virtual windowing system, I've
  1337. added text-mode support into the "graphics" routines.
  1338.  
  1339. There are some quirks to these routines, since text mode doesn't work the
  1340. same way as graphics mode.  For one thing, each "pixel" is actually an entire
  1341. character.  The default pixel is a solid block character, CHR$(219).  You can
  1342. change this, however:
  1343.  
  1344.    G0SetBlock Ch%      ' set ASCII code (use ASC(Ch$) to convert from string)
  1345.    Ch% = G0GetBlock%   ' get ASCII code (use CHR$(Ch) to convert to a string)
  1346.  
  1347. Since a pixel consists of a character with both foreground and background
  1348. colors, the "get pixel" routine has been altered to accordingly:
  1349.  
  1350.    G0GetPel X%, Y%, Ch%, Fore%, Back%
  1351.  
  1352. Finally, let's consider the "set mode" command.  If you pass it a zero, the
  1353. current mode will be used as-is.  This is useful in case you've already set
  1354. up a desired mode.
  1355.  
  1356. Any other mode number will be assumed to be a BIOS video mode which should be
  1357. set.  If you feel like initializing the screen mode for some reason, it may
  1358. be useful to know that 3 is the normal color mode (for CGA, EGA, VGA, etc)
  1359. and 7 is the normal mono mode (for MDA and Hercules).  These provide 80x25
  1360. text.  If you wish to take advantage of 43-row EGA or 50-row VGA text modes,
  1361. you must set them up in advance (using the BASIC statements SCREEN and WIDTH)
  1362. before calling G0Mode with a zero.
  1363.  
  1364. If you have a SuperVGA or other adapter which supports unusual text modes,
  1365. you can use the mode command to switch to the appropriate mode.  On my Boca
  1366. SuperVGA, for example, mode &H26 provides 80x60 text, and mode &H22 provides
  1367. 132x44.  The G0 routines are designed to support any text resolution up to
  1368. 255x255, provided that the BIOS updates the appropriate memory locations when
  1369. a mode set is done.  This should be true for any special EGA or VGA-based
  1370. text modes.
  1371.  
  1372.    G0Mode ModeNr%
  1373.  
  1374. I will probably add another set of text-mode routines in the future.
  1375. Provided I can get information on how to control an MDA/Herc cursor directly,
  1376. I will add a set of routines that will work only on MDA and Herc displays.
  1377. This will enable you to write programs to support dual-monitor setups, using
  1378. the new routines for the mono display and the existing routines for the color
  1379. display.  Can anyone tell me how to program the video chip directly or point
  1380. me to a source for such information?
  1381.  
  1382.                          Graphics: Printer Routines                    page 32
  1383.  
  1384.  
  1385.  
  1386. The BasWiz printer routines allow you to work with a printer using the same
  1387. convenient methods you'd use on a screen.  The image is created with the
  1388. usual G# routines (using mode N2), but the results are kept in a buffer in
  1389. memory (about 37K bytes) rather than being displayed directly.  The image can
  1390. be previewed on a VGA or printed out at your convenience, to any printer or
  1391. even a file.  The results will take up a single printer page, assuming the
  1392. usual 8.5" x 11" paper is used.
  1393.  
  1394. Printing a finished page works like this:
  1395.  
  1396.    GN2Print Device$
  1397.  
  1398. The Device$ variable should be set to the name of the device:
  1399.  
  1400.    LPT1    parallel printer on port 1
  1401.    LPT2    parallel printer on port 2
  1402.    LPT3    parallel printer on port 3
  1403.    COM1    serial printer on port 1
  1404.    COM2    serial printer on port 2
  1405.  
  1406. Instead of using a device name, you can also use a file name, to store the
  1407. results for later printing.  Output is done using BASIC file handling, so it
  1408. would be a good idea to provide an ON ERROR GOTO trap in case of problems.
  1409. The FREEFILE function is used, so you don't have to worry about conflicts
  1410. with any files in use by your program.
  1411.  
  1412. Getting a page layout just right can consume a lot of paper.  Fortunately,
  1413. there's a "preview" routine that allows you to display the results on a VGA.
  1414. The display will be sideways, allowing the whole page to be seen at once.
  1415. This will exactly match the printed output in N2 mode.  Here's how it works:
  1416.  
  1417.    G11Mode 1               ' set SCREEN 11 (VGA graphics mode, 640x480 x2)
  1418.    GN2Display              ' display the page
  1419.    DO                      ' wait for a key to be pressed
  1420.    LOOP UNTIL LEN(INKEY$)  '
  1421.    G11Mode 0               ' set SCREEN 0 (text mode)
  1422.  
  1423. The GN2Write and GN2WriteLn printer routines are unlike the display versions
  1424. of the same routines in that they don't scroll.  These routines only allow
  1425. you to design one page at a time.
  1426.  
  1427. Before using GN2Write or GN2WriteLn routines, you must choose a font with
  1428. GN2Font.  These are the same fonts as used in G#Banner:
  1429.  
  1430.     0     8 x 8        80 text rows
  1431.     1     8 x 14       45 text rows
  1432.     2     8 x 16       40 text rows
  1433.  
  1434. The current font can be retrieved with GN2GetFont%.  The result will be
  1435. meaningless if the font was never set with GN2Font.
  1436.  
  1437.                          Graphics: A Little Geometry                   page 33
  1438.  
  1439.  
  1440.  
  1441. The increasing capabilities of computer graphics systems has left many of us
  1442. in the dust.  It's great to be able to run dazzling applications or to doodle
  1443. with a "paint" program, but many of us find it difficult to design appealing
  1444. images of our own.  Becoming an artist is perhaps a bit more than most of us
  1445. are willing to take on!  It is important to remember, however, that computers
  1446. are wonderful number-crunchers.  With a little application of plane geometry,
  1447. you can have the computer take on much of the work for you-- and after all,
  1448. isn't that why we have computers in the first place?
  1449.  
  1450. A complete review of plane geometry is a bit beyond the scope of this text.
  1451. However, I'm going to run through some of the things I think you'll find most
  1452. useful.  I'd also like to suggest that you might dig out your old textbooks
  1453. or rummage through your local used book store.  It may have seemed like a dry
  1454. subject at the time, but when you can watch the results growing on your
  1455. computer screen, you will have a much better idea of how geometry can be
  1456. useful to you-- and it can be surprisingly fun, too!
  1457.  
  1458. In geometry talk, a "point" doesn't have any actual size.  In our case, we
  1459. want to apply geometry to physical reality, namely the computer screen.  As
  1460. far as we're concerned, a "point" will be an individual graphics dot, also
  1461. called a "pel" or "pixel" (for "picture element").  We can safely dispense
  1462. with such formalities for our applications, for the most part.
  1463.  
  1464. The most important thing about a point is that it has a location!  Ok, that
  1465. may not seem staggering, but it happens that there are a number of ways of
  1466. specifying that location.  The most common method is called the Cartesian
  1467. coordinate system.  It is based on a pair of numbers: X, which represents the
  1468. distance along a horizontal line, and Y, which represents the distance along
  1469. a vertical line.  Consider the CGA in SCREEN 2, for instance.  It has a
  1470. coordinate system where X can be 0 - 639 and Y can be 0 - 199.  The points
  1471. are mapped on kind of an invisible grid.
  1472.  
  1473. The Cartesian coordinate system makes it easy to visualize how a given point
  1474. relates to other points on the same plane (or screen).  It is particularly
  1475. useful for drawing lines.  Horizontal and vertical lines become a cinch: just
  1476. change the X value to draw horizontally, or the Y value to draw vertically.
  1477. Squares and rectangles (or boxes) can be formed by a combination of such
  1478. lines.  You can define an area of the screen in terms of an imaginary box
  1479. (as GET and PUT do) with nice, clean boundaries.  When we get to diagonal
  1480. lines, it's a bit more of a nuisance, but still easy enough with the proper
  1481. formula.  That means we can do triangles too.  Curves are worse... when it
  1482. comes to even a simple circle or ellipse, the calculations start to get on
  1483. the messy side.  For things like that, though, there is an alternative.
  1484.  
  1485. Another way of describing the location of a point is by Polar coordinates.
  1486. In Cartesian coordinates, the location is specified by its horizontal and
  1487. vertical distances from the "origin" or reference point, (0,0).  In Polar
  1488. coordinates, the location is specified by its distance and angle from the
  1489. origin.  Think of it as following a map: Cartesian coordinates tell you how
  1490. many blocks down and how many blocks over the point is, whereas Polar
  1491. coordinates tell you in which direction the point is and how far away it is
  1492. "as the crow flies".
  1493.  
  1494.                          Graphics: A Little Geometry                   page 34
  1495.  
  1496.  
  1497.  
  1498. The Polar coordinate system is great for describing many kinds of curves,
  1499. much better than Cartesian.  For example, a circle is defined as all of the
  1500. points at a given (fixed) distance from a center point.  Polar coordinates
  1501. include both a distance and an angle, and we've already got the distance, so
  1502. all we need to do is plot points at all of the angles on a circle.
  1503. Technically, there is an infinite number of angles, but since our points
  1504. don't follow the mathematical definition (they have a size), we don't have to
  1505. worry about that.
  1506.  
  1507. Let me digress for a moment to talk about angles.  In BASIC, angles are
  1508. specified in "radians".  People more often use "degrees".  Fortunately, it
  1509. isn't hard to convert from one to the other.  Both may be visualized on a
  1510. circle.  In radians, the sum of the angles in a circle is twice pi.  In
  1511. degrees, the sum of the angles is 360.  That's something like this:
  1512.  
  1513.  
  1514.                           90 deg, 1/2 * pi rad
  1515.                                 /---|---\
  1516.                                /    |    \
  1517.                               /     |     \
  1518.                 180 degrees   |___  .  ___|    0 deg, 0 rad; or...
  1519.                 pi radians    |           |  360 deg, 2 * pi rad
  1520.                               \     |     /
  1521.                                \    |    /
  1522.                                 \---|---/
  1523.                           270 deg, 3/2 * pi rad
  1524.  
  1525.  
  1526. Ok, so that's a grotesquely ugly circle!  Hopefully it shows the important
  1527. thing, though.  Angles start at zero on the extreme right and get larger as
  1528. they work around counter-clockwise.  The places marked on the "circle" are
  1529. places where lines drawn horizontally and vertically through the center
  1530. intersect the outside of the circle.  These serve as a useful reference
  1531. point, especially in that they help show how the angles can be construed from
  1532. a Cartesian viewpoint.
  1533.  
  1534. So much for angles.  I'll go into conversion formulae, the value of pi, and
  1535. other good junk a bit later on.  Right now, let's get back to our discussion
  1536. of Polar coordinates.
  1537.  
  1538. I've explained how the Polar system makes it easy to draw a circle.  Since
  1539. you can vary the range of angles, it's equally simple to draw an arc.  If you
  1540. wanted to make a pie chart, you might want to join the ends of the arcs to
  1541. the center of the circle, in which case you'd keep the angle constant (at the
  1542. ends of the arc) and plot by changing the distance from zero to the radius.
  1543. Circles are also handy for drawing equilateral polygons... you know, shapes
  1544. with sides of equal length: triangle, square, pentagon, hexagon, etc.  In
  1545. this case, the best features of the Cartesian and Polar systems can be joined
  1546. to accomplish something that would be difficult in either alone.
  1547.  
  1548.                          Graphics: A Little Geometry                   page 35
  1549.  
  1550.  
  1551.  
  1552. The starting point for these polygons is the circle.  Imagine that the
  1553. polygon is inside a circle, with the vertices (pointy ends, that is, wherever
  1554. the sides meet) touching the edge of the circle.  These are equilateral
  1555. polygons, so all of the sides and angles are the same size.  Each of the
  1556. vertices touches the circle, and each does it at exactly the same distance
  1557. from each other along the arc of the circle.  All of this detail isn't
  1558. precisely necessary, but I hope it makes the reasoning a bit more clear!
  1559.  
  1560. The circle can be considered as being divided by the polygon into a number of
  1561. arcs that corresponds to the number of vertices (and sides) the polygon has.
  1562. Think of a triangle inside a circle, with the tips all touching the circle.
  1563. If you ignore the area inside the triangle, you will see that the circle is
  1564. divided into three equal arcs.  The same property is true of any equilateral
  1565. polygon.  As a matter of fact, as the number of vertices goes up, the circle
  1566. is partitioned into more, but smaller, arcs... so that a polygon with a large
  1567. enough number of vertices is effectively a circle itself!
  1568.  
  1569. Anyway, the important thing is the equal partitioning.  We know how many
  1570. angles, be they degrees or radians, are in a circle.  To get the points of a
  1571. polygon, then... well, we already know the "distance" part, that's the same
  1572. as the radius.  The angles can be calculated by dividing the angles in the
  1573. whole circle by the number of vertices in the desired polygon.  Trying that
  1574. case with the triangle, assuming a radius of 20 (why not), and measuring in
  1575. degrees, that would give us the Polar points (20, 0), (20, 120), (20, 240).
  1576. To make this a triangle, we need to connect the points using lines, which is
  1577. easy in Cartesian coordinates.  Since the computer likes Cartesian anyway, we
  1578. just convert the Polar coordinates to Cartesian, draw the lines, and viola!
  1579.  
  1580. That's essentially the method used by the G#Polygon routines.  It's very
  1581. simple in practice, but I haven't seen it elsewhere... probably because
  1582. people forget about the Polar coordinate system, which is what makes it all
  1583. come together.  Polar coordinates also have simple equations for figures that
  1584. look like daisies, hearts, and other unusual things.  See "Equations, Etc"
  1585. and ROSES.BAS for more information.
  1586.  
  1587. On a side note, the Cartesian system isn't used by all computers, although
  1588. it's the most common.  Cartesian coordinates are the standard for what is
  1589. called "raster" displays.  The Polar coordinate system is used on "vector"
  1590. displays.  One example of a vector display that you may have seen is the old
  1591. Asteroids video arcade game.  Vector displays tend to be used for drawing
  1592. "framework" pictures where the image must be very sharp (unlike in raster
  1593. images, the diagonal lines aren't jagged, since there's no raster "grid").
  1594.  
  1595.                           Graphics: Equations, Etc                     page 36
  1596.  
  1597.  
  1598.  
  1599. In this section, I'm going to list a number of equations and so forth.  Some
  1600. of them will be useful to you in experimenting with Polar coordinates.  Some
  1601. of them provide formulae for things that are already in BasWiz, but which you
  1602. might like to understand better.  Some of them are just for the heck of it...
  1603. note that not all of this information may be complete enough for you to just
  1604. use without understanding it.
  1605.  
  1606. One problem is... if you try to draw a circle, for instance, it will come out
  1607. looking squashed in most SCREEN modes.  Remember we said our points, unlike
  1608. mathematical points, have a size?  In most graphics modes, the points are
  1609. effectively wider than they are high, so a real circle looks like an ellipse.
  1610.  
  1611. Another problem is that these equations are based on an origin of (0,0) which
  1612. is assumed to be at the center of the plane.  In our case, (0,0) is at the
  1613. upper right edge, which also makes the Y axis (vertical values) effectively
  1614. upside-down.  This isn't necessarily a problem, but sometimes it is!  Adding
  1615. appropriate offsets to the plotted X and Y coordinates often fixes it.  In
  1616. the case of Y, you may need to subtract the value from the maximum Y value to
  1617. make it appear right-side-up.
  1618.  
  1619. The displayed form of these equations may contain "holes", usually again
  1620. because the points have a size, and/or since we try to use integer math to
  1621. speed things up.  If the screen had infinite resolution, this would not be a
  1622. problem... meanwhile (!), getting around such problems takes fiddlin'.
  1623.  
  1624. There are other problems, mostly due to forcing these simplified-universe
  1625. theoretical equations into practical use.  It's a lot easier to shoehorn in
  1626. these simple equations than to use more accurate mathematical descriptions,
  1627. though... a -lot- easier.  So a few minor quirks can be ignored!
  1628.  
  1629. With those disclaimers, here's the scoop on some handy equations.
  1630.  
  1631.    Polar coordinates may be expressed as (R, A), where R is radius or
  1632.    distance from the origin, and A is the angle.
  1633.  
  1634.    Cartesian coordinates may be expressed as (X, Y), where X is the distance
  1635.    along the horizontal axis and Y is the distance along the vertical axis.
  1636.  
  1637.    Polar coordinates can be converted to Cartesian coordinates like so:
  1638.       X = R * COS(A)
  1639.       Y = R * SIN(A)
  1640.  
  1641.    Angles may be expressed in radians or degrees.  BASIC prefers radians.
  1642.    Radians are based on PI, with 2 * PI radians in a circle.  There are 360
  1643.    degrees in a circle.  Angles increase counter-clockwise from a 3:00 clock
  1644.    position, which is the starting (zero) angle.  Angles can wrap around: 720
  1645.    degrees is the same as 360 degrees or 0 degrees, just as 3:00 am is at the
  1646.    same clock position as 3:00 pm.
  1647.  
  1648.    Angles may be converted between degrees and radians as follows:
  1649.       radians = degrees * PI / 180
  1650.       degrees = radians * 180 / PI
  1651.  
  1652.                           Graphics: Equations, Etc                     page 37
  1653.  
  1654.  
  1655.  
  1656.  
  1657.    The value PI is approximately 3.14159265358979.  For most graphics
  1658.    purposes, a simple 3.141593 should do quite nicely.  The true value of PI
  1659.    is an irrational number (the decimal part repeats forever, as near as
  1660.    anyone can tell).  It has been calculated out to millions of decimal
  1661.    points by people with a scientific bent (and/or nothing better to do)!
  1662.  
  1663. Line Drawing:
  1664.  
  1665.    One of the convenient ways of expressing the formula of a line (Cartesian
  1666.    coordinates) is:
  1667.       Y = M * X + B
  1668.  
  1669.    Given the starting and ending points for the line, M (the slope,
  1670.    essentially meaning the angle of the line) can be determined by:
  1671.       M = (Y2 - Y1) / (X2 - X1)
  1672.  
  1673.    The B value is called the Y-intercept, and indicates where the line
  1674.    intersects with the Y-axis.  Given the ingredients above, you can
  1675.    calculate that as:
  1676.       B = Y1 - M * X1
  1677.  
  1678.    With this much figured out, you can use the original formula to calculate
  1679.    the appropriate Y values, given a FOR X = X1 TO X2 sort of arrangement.
  1680.    If the slope is steep, however, this will result in holes in the line.  In
  1681.    that case, it will be smoother to recalculate the formula in terms of the
  1682.    X value and run along FOR Y = Y1 TO Y2... in that case, restate it as:
  1683.       X = (Y - B) / M
  1684.  
  1685.    Keep an eye on conditions where X1 = X2 or Y1 = Y2!  In those cases,
  1686.    you've got a vertical or horizontal line.  Implement those cases by simple
  1687.    loops to improve speed and to avoid dividing by zero.
  1688.  
  1689.  
  1690.  
  1691. Circle Drawing:
  1692.  
  1693.    The Cartesian formula gets messy, especially due to certain aspects of the
  1694.    display that are not accounted for (mainly that pixels, unlike theoretical
  1695.    points, have a size and shape which is usually rectangular).  The Polar
  1696.    formula is trivial, though.  The radius should be specified to the circle
  1697.    routine, along with the center point.  Do a FOR ANGLE! = 0 TO 2 * PI! STEP
  1698.    0.5, converting the resulting (Radius, Angle) coordinates to Cartesian,
  1699.    then adding the center (X,Y) as an offset to the result.  The appropriate
  1700.    STEP value for the loop may be determined by trial and error.  Smaller
  1701.    values make better circles but take more time.  Larger values may leave
  1702.    "holes" in the circle.
  1703.  
  1704.                           Graphics: Equations, Etc                     page 38
  1705.  
  1706.  
  1707.  
  1708. Spiral Drawing:
  1709.  
  1710.    If you use Polar coordinates, this is easy.  Just treat it like a circle,
  1711.    but decrease the radius as you go along to spiral in... or increase the
  1712.    radius as you go along if you prefer to spiral out.
  1713.  
  1714.  
  1715.  
  1716. Polygon Drawing:
  1717.  
  1718.    I've already discussed that, so I'll leave it as an exercise... or of
  1719.    course you can examine my source code if you register BasWiz!  The polygon
  1720.    routines are in BASIC, except for the line-drawing parts.
  1721.  
  1722.  
  1723.  
  1724. Flower Drawing:
  1725.  
  1726.    This sort of thing would be rather difficult to do using strictly
  1727.    Cartesian methods, but with Polar coordinates, no problem.  Here we
  1728.    calculate the radius based on the angle, using something like:
  1729.  
  1730.       FOR Angle! = 0 TO PI! * 2 STEP .01
  1731.  
  1732.    (a low STEP value is a good idea).  The radius is calculated like so:
  1733.  
  1734.       Radius! = TotalRadius! * COS(Petals! * Angle!)
  1735.  
  1736.    The Petals! value specifies how many petals the flower should have.  If it
  1737.    is odd, the exact number of petals will be generated; if even, twice that
  1738.    number will be generated.
  1739.  
  1740.    These figures are technically called "roses", although they more resemble
  1741.    daisies.  Try the ROSES.BAS program to see how they look.
  1742.  
  1743.  
  1744.  
  1745. Other Drawing:
  1746.  
  1747.    Experiment!  There are all sorts of interesting things you can do with the
  1748.    Polar coordinate system in particular.  Dig up those old Geometry texts or
  1749.    see if your Calculus books review it.  If you've kept well away from math,
  1750.    try your local library or used book store.
  1751.  
  1752.                         Memory Management and Pointers                 page 39
  1753.  
  1754.  
  1755.  
  1756. On the whole, BASIC is easily a match for any other language, as far as
  1757. general-purpose programming goes.  There is one major lack, however-- a set
  1758. of valuable features that is supported by most other languages, but was
  1759. inexplicably left out of BASIC.  Perhaps Microsoft felt it was too advanced
  1760. and dangerous for a so-called "beginner's" language.  In truth, using
  1761. pointers and memory management takes a little understanding of what you're
  1762. doing-- the compiler can't protect you from all of your mistakes.  However,
  1763. they can be extraordinarily useful for many things, so I have added these
  1764. capabilities to BasWiz.
  1765.  
  1766. A "pointer" is essentially just the address of an item.  It is useful in two
  1767. respects: it allows you to pass just the pointer, rather than the whole item
  1768. (be it a TYPEd variable, normal variable, entire array, or whatever) to a
  1769. subprogram.  This is faster and more memory-efficient than the alternatives.
  1770. Secondly, a pointer combined with memory management allows you to allocate
  1771. and deallocate memory "on the fly", in just the amount you need.  You don't
  1772. have to worry about DIMensioning an array too large or too small, or even
  1773. with how large each element of the array should be, for example.  You can
  1774. determine that when your program -runs-, rather than at compile time, and set
  1775. up your data structures accordingly.  You can also create a large variety of
  1776. data structures, such as trees and linked lists, which would be difficult and
  1777. cumbersome to emulate using BASIC alone.
  1778.  
  1779. The BasWiz memory/pointer routines allow you to allocate and deallocate
  1780. memory; fill, copy or move a block of memory; get or put a single character
  1781. according to a pointer; and convert back and forth between a segment/offset
  1782. address and a pointer.
  1783.  
  1784. Pointers are kept in LONG integers, using an absolute memory addressing
  1785. scheme.  This means that you can manipulate pointers just like any ordinary
  1786. LONG integer, e.g. to move to the next memory address, just add one.  Since
  1787. you can convert from a segment/offset address to a pointer and you can copy
  1788. information from one pointer to another, you can move information back and
  1789. forth between allocated memory and a TYPEd variable, numeric variable, or
  1790. array.  You can even do things like set a pointer to screen memory and
  1791. transfer the screen into a variable or vice versa!  Or implement your own
  1792. "far string" routines, hierarchical evaluations, or any number of other
  1793. things.  Pointers are incredibly powerful!
  1794.  
  1795. Note that there are different ways of representing the same segment/offset
  1796. address, but only one absolute pointer representation.  If you need to
  1797. compare two addresses, using pointers is terrific.  However, it's good to
  1798. keep in mind that an segment/offset address may -appear- to change if you
  1799. convert it to a pointer and then back to a segment/offset address.  When you
  1800. convert from a pointer to a segment/offset, the segment will be maximized and
  1801. the offset minimized.  So, for example, 0040:001C will turn into 0041:000C.
  1802.  
  1803. Although the byte count for these routines is handled through a LONG integer,
  1804. the routines handle a maximum of 65,520 bytes at a time.  In other words, a
  1805. pointer can only access a bit less than 64K at a time.  If I get enough
  1806. requests to extend this range, I will do so.  Meantime, that's the limit!
  1807.  
  1808.                         Memory Management and Pointers                 page 40
  1809.  
  1810.  
  1811.  
  1812. There are two routines which take care of memory management.  These allow you
  1813. to allocate or deallocate memory.  Note that if you allocate too much memory,
  1814. QuickBASIC won't have any memory to work with!  Use the BASIC function
  1815. "SETMEM" to see how much memory is available before going hog-wild.
  1816.  
  1817. You can allocate memory like so:
  1818.  
  1819.    MAllocate Bytes&, Ptr&, ErrCode%
  1820.  
  1821. If there isn't enough memory available, an error code will be returned.
  1822. Otherwise, Ptr& will point to the allocated memory.  Memory is allocated in
  1823. chunks of 16 bytes, so there may be some memory wasted if you choose a number
  1824. of bytes that isn't evenly divisible by 16.
  1825.  
  1826. When you are finished with that memory, you can free it up by deallocation:
  1827.  
  1828.    MDeallocate Ptr&, ErrCode%
  1829.  
  1830. An error code will be returned if Ptr& doesn't point to previously allocated
  1831. memory.
  1832.  
  1833. In the best of all possible worlds, there would be a third routine which
  1834. would allow you to reallocate or resize a block of memory.  However, due to
  1835. certain peculiarities of QuickBASIC, I was unable to implement that.  You can
  1836. simulate such a thing by allocating a new area of memory of the desired size,
  1837. moving an appropriate amount of information from the old block to the new,
  1838. and finally deallocating the old block.
  1839.  
  1840. Once you've allocated memory, you can move any sort of information in or out
  1841. of it except normal strings-- fixed-length strings, TYPEd values, arrays, or
  1842. numeric values.  To do that, you use BASIC's VARSEG and VARPTR functions on
  1843. the variable.  Convert the resulting segment/offset address to a pointer:
  1844.  
  1845.    TSeg% = VARSEG(Variable)
  1846.    TOfs% = VARPTR(Variable)
  1847.    VariablePtr& = MJoinPtr&(TSeg%, TOfs%)
  1848.  
  1849. Moving the information from one pointer to another works like so:
  1850.  
  1851.    MMove FromPtr&, ToPtr&, Bytes&
  1852.  
  1853. For STRING or TYPEd values, you can get the number of bytes via the LEN
  1854. function.  For numeric values, the following applies:
  1855.  
  1856.    Type       Bytes per value
  1857.    =======    ===============
  1858.    INTEGER           2
  1859.    LONG              4
  1860.    SINGLE            4
  1861.    DOUBLE            8
  1862.  
  1863.                         Memory Management and Pointers                 page 41
  1864.  
  1865.  
  1866.  
  1867. The "memory move" (MMove) routine is good for more than just transferring
  1868. information between a variable and allocated memory, of course.  Pointers can
  1869. refer to any part of memory.  For instance, CGA display memory starts at
  1870. segment &HB800, offset 0, and goes on for 4000 bytes in text mode.  That
  1871. gives a pointer of &HB8000.  You can transfer from the screen to a variable
  1872. or vice versa.  For that matter, you can scroll the screen up, down, left, or
  1873. right by using the appropriate pointers.  Add two to the pointer to move it
  1874. to the next character or 160 to move it to the next row.  As I said, pointers
  1875. have all kinds of applications!  You don't need to worry about overlapping
  1876. memory-- if the two pointers, combined with the bytes to move, overlap at
  1877. some point, why, the MMove routine takes care of that for you.  It avoids
  1878. pointer conflicts.  MMove is a very efficient memory copying routine.
  1879.  
  1880. Suppose you've got a pointer and would like to convert it back to the
  1881. segment/offset address that BASIC understands.  That's no problem:
  1882.  
  1883.    MSplitPtr Ptr&, TSeg%, TOfs%
  1884.  
  1885. You might also want to fill an area of memory with a specified byte value,
  1886. perhaps making freshly-allocated memory zeroes, for example:
  1887.  
  1888.    MFill Ptr&, Value%, Bytes&
  1889.  
  1890. Finally, there may be occasions when you might want to transfer a single
  1891. character.  Rather than going through putting the character into a STRING*1,
  1892. getting the VARSEG/VARPTR, and using MJoinPtr&, there is a simpler method:
  1893.  
  1894.    MPutChr Ptr&, Ch$
  1895.    Ch$ = MGetChr$(Ptr&)
  1896.  
  1897. Hopefully, this will give you some ideas to start with.  I'll expand on the
  1898. uses of pointers and give further examples in future versions of BasWiz.
  1899. There are many, many possible uses for such capabilities.  Pointers and
  1900. memory management used to be the only real way in which BASIC could be
  1901. considered inferior to other popular languages-- that is no more!
  1902.  
  1903. NOTE:
  1904.    QuickBASIC may move its arrays around in memory!  Don't expect the address
  1905.    of an array to remain constant while your program is running.  Be sure to
  1906.    get the VARSEG/VARPTR for arrays any time you're not sure they're in the
  1907.    same location.  Among the things which can cause arrays to move are use of
  1908.    DIM, REDIM, or ERASE, and possibly calls to SUBs or FUNCTIONs.  I'm not
  1909.    sure if anything else may cause the arrays to move, so be cautious!
  1910.  
  1911.                               Telecommunications                       page 42
  1912.  
  1913.  
  1914.  
  1915. BASIC is unusual among languages in that it comes complete with built-in
  1916. telecommunications support.  Unfortunately, that support is somewhat crude.
  1917. Amongst other problems, it turns off the DTR when the program SHELLs or ends,
  1918. making it difficult to write doors for BBSes or good terminal programs.  It
  1919. also requires use of the /E switch for error trapping, since it generates
  1920. errors when line noise is encountered, and doesn't provide much control.  It
  1921. doesn't even support COM3 and COM4, which have been available for years.
  1922.  
  1923. BasWiz rectifies these troubles.  It allows comprehensive control over
  1924. communications, includes COM3 and COM4, and doesn't require error trapping.
  1925. It won't fiddle with the DTR unless you tell it to do so.  The one limitation
  1926. is that you may use only a single comm port at a time.
  1927.  
  1928. Before you can use communications, you must initialize the communications
  1929. handler.  If you didn't have BasWiz, you would probably use something like:
  1930.  
  1931.    OPEN "COM1:2400,N,8,1,RS,CS,DS" AS #1
  1932.  
  1933. With BasWiz, you do not have to set the speed, parity, and so forth.
  1934. Communications will proceed with whatever the current settings are, unless
  1935. you choose to specify your own settings.  When you initialize the comm
  1936. handler, you specify only the port number (1-4) and the size of the input and
  1937. output buffers (1-32,767 bytes):
  1938.  
  1939.    TCInit Port, InSize, OutSize, ErrCode
  1940.  
  1941. The size you choose for the buffers should be guided by how your program will
  1942. use communications.  Generally, a small output buffer of 128 bytes will be
  1943. quite adequate.  You may wish to expand it up to 1,500 bytes or so if you
  1944. expect to write file transfer protocols.  For the input buffer, you will want
  1945. perhaps 512 bytes for normal use.  For file transfer protocols, perhaps 1,500
  1946. bytes would be better.  If a high baud rate is used, or for some other reason
  1947. you might not be emptying the buffer frequently, you may wish to expand the
  1948. input buffer size to 4,000 bytes or more.
  1949.  
  1950. When you are done with the telecomm routines, you must terminate them.  In
  1951. BASIC, this would be done with something like:
  1952.  
  1953.    CLOSE #1
  1954.  
  1955. With the BasWiz routines, though, you would use this instead:
  1956.  
  1957.    TCDone
  1958.  
  1959. The BasWiz "TCDone" does not drop the DTR, unlike BASIC's "CLOSE".  This
  1960. means that the modem will not automatically be told to hang up.  With BasWiz,
  1961. you have complete control over the DTR with the TCDTR routine.  Use a value
  1962. of zero to drop the DTR or nonzero to raise the DTR:
  1963.  
  1964.    TCDTR DTRstate
  1965.  
  1966.                               Telecommunications                       page 43
  1967.  
  1968.  
  1969.  
  1970. You may set the speed of the comm port to any baud rate from 1-65,535.  If
  1971. you will be dealing with comm programs that were not written using BasWiz,
  1972. you may wish to restrict that to the more common rates: 300, 1200, 2400,
  1973. 4800, 9600, 19200, 38400, and 57600.
  1974.  
  1975.    TCSpeed Baud&
  1976.  
  1977. The parity, word length, and stop bits can also be specified.  You may use
  1978. 1-2 stop bits, 6-8 bit words, and parity settings of None, Even, Odd, Mark,
  1979. or Space.  Nearly all BBSes use settings of None, 8 bit words, and 1 stop
  1980. bit, although you will sometimes see Even, 7 bit words, and 1 stop bit.  The
  1981. other capabilities are provided for dealing with mainframes and other systems
  1982. which may require unusual communications parameters.
  1983.  
  1984. When specifying parity, only the first character in the string is used, and
  1985. uppercase/lowercase distinctions are ignored.  Thus, using either "none" or
  1986. "N" would specify that no parity is to be used.
  1987.  
  1988.    TCParms Parity$, WordLength, StopBits
  1989.  
  1990. If your program needs to be aware of when a carrier is present, it can check
  1991. the carrier detect signal from the modem with the TCCarrier function.  This
  1992. function returns zero if no carrier is present:
  1993.  
  1994.    IF TCCarrier THEN
  1995.       PRINT "Carrier detected"
  1996.    ELSE
  1997.       PRINT "No carrier"
  1998.    END IF
  1999.  
  2000. Suppose, though, that you need to know immediately when someone has dropped
  2001. the carrier?  It wouldn't be too convenient to have to spot TCCarrier
  2002. functions all over your program!  In that case, try the "ON TIMER" facility
  2003. provided by BASIC for keeping an eye on things.  It will enable you to check
  2004. the carrier at specified intervals and act accordingly.  Here's a brief
  2005. framework for writing such code:
  2006.  
  2007.    ON TIMER(30) GOSUB CarrierCheck
  2008.    TIMER ON
  2009.    ' ...your program goes here...
  2010. CarrierCheck:
  2011.    IF TCCarrier THEN              ' if the carrier is present...
  2012.       RETURN                      ' ...simply resume where we left off
  2013.    ELSE                           ' otherwise...
  2014.       RETURN Restart              ' ...return to the "Restart" label
  2015.    END IF
  2016.  
  2017.                               Telecommunications                       page 44
  2018.  
  2019.  
  2020.  
  2021. To get a character from the comm port, use the TCInkey$ function:
  2022.  
  2023.    ch$ = TCInkey$
  2024.  
  2025. To send a string to the comm port, use TCWrite:
  2026.  
  2027.    TCWrite St$
  2028.  
  2029. If you are dealing strictly with text, you may want to have a carriage return
  2030. and a linefeed added to the end of the string.  No problem:
  2031.  
  2032.    TCWriteLn St$
  2033.  
  2034. Note that the length of the output buffer affects how the TCWrite and
  2035. TCWriteLn routines work.  They don't actually send string directly to the
  2036. comm port.  Instead, they put the string into the output buffer, and it gets
  2037. sent to the comm port whenever the comm port is ready.  If there is not
  2038. enough room in the output buffer for the whole string, the TCWrite/TCWriteLn
  2039. routines are forced to wait until enough space has been cleared for the
  2040. string.  This can delay your program.  You can often avoid this delay simply
  2041. by making the output buffer larger.
  2042.  
  2043. If you'd like to know how many bytes are waiting in the input buffer or
  2044. output buffer, there are functions which will tell you:
  2045.  
  2046.    PRINT "Bytes in input buffer:"; TCInStat
  2047.    PRINT "Bytes in output buffer:"; TCOutStat
  2048.  
  2049. Finally, if you would like to clear the buffers for some reason, you can do
  2050. that too.  The following routines clear the buffers, discarding anything
  2051. which was waiting in them:
  2052.  
  2053.    TCFlushIn
  2054.    TCFlushOut
  2055.  
  2056. Don't forget to use TCDone to terminate the comm handler before ending your
  2057. program!  If you do, the computer will lock up.  Worse, it may not lock up
  2058. immediately, so forgetting TCDone can be very unpleasant.
  2059.  
  2060.                               Telecommunications                       page 45
  2061.  
  2062.  
  2063.  
  2064. Finally, there is a routine which allows you to handle ANSI codes in a
  2065. window.  Besides the IBM semi-ANSI display code subset, mock-ANSI music is
  2066. allowed.  This routine is designed as a subroutine that you can access via
  2067. GOSUB, since there are a number of variables that the routine needs to
  2068. maintain that would be a nuisance to pass as parameters, and QuickBASIC
  2069. unfortunately can't handle SUBs in $INCLUDE files (so SHARED won't work).
  2070. To use it, either include ANSI.BAS directly in your code, or use:
  2071.  
  2072.    REM $INCLUDE: 'ANSI.BAS'
  2073.  
  2074. Set St$ to the string to process, set Win% to the handle of the window to
  2075. which to display, and set Music% to zero if you don't want sounds or -1 if
  2076. you do want sounds.  Then:
  2077.  
  2078.    GOSUB ANSIprint
  2079.  
  2080. Note that the virtual screen tied to the window must be at least an 80 column
  2081. by 25 row screen, since ANSI expects that size.  You are also advised to have
  2082. an ON ERROR trap if you use ANSIprint with Music% = -1, just in case a "bad"
  2083. music sequence slips through and makes BASIC unhappy.  Check for ERR = 5
  2084. (Illegal Function Call).  I'll add a music handler later to avoid this.
  2085.  
  2086. To get some idea of how these routines all tie together in practice, see the
  2087. TERM.BAS example program.  It provides a simple "dumb terminal" program to
  2088. demonstrate the BasWiz comm handler.  Various command-line switches are
  2089. allowed:
  2090.  
  2091.    /43     use 43-line mode (EGA and VGA only)
  2092.    /COM2   use COM2
  2093.    /COM3   use COM3
  2094.    /COM4   use COM4
  2095.    /300    use 300 baud
  2096.    /1200   use 1200 baud
  2097.    /QUIET  ignore "ANSI" music
  2098.  
  2099. By default, the TERM.BAS program will use COM1 at 2400 baud with no parity, 8
  2100. bit words and 1 stop bit.  You can exit the program by pressing Alt-X.
  2101.  
  2102.                               Telecommunications                       page 46
  2103.  
  2104.  
  2105.  
  2106. The Xmodem file transfer protocol is currently supported for sending files
  2107. only.  It automatically handles any of the usual variants on the Xmodem
  2108. protocol: 128-byte or 1024-byte blocks, plus checksum or CRC error detection.
  2109. In other words, it is compatible with Xmodem (checksum), Xmodem CRC, and
  2110. Xmodem-1K (single-file Ymodem-like variant).
  2111.  
  2112. There are only two routines which must be used to transfer a file.  The first
  2113. is called once to initialize the transfer.  The second is called repeatedly
  2114. until the transfer is finished or aborted.  Complete status information is
  2115. returned by both routines.  You can ignore most of this information or
  2116. display it any way you please.
  2117.  
  2118. The initialization routine looks like this:
  2119.  
  2120.    StartXmodemSend Handle, Protocol$, Baud$, MaxRec, Record, EstTime$, ErrCode
  2121.  
  2122. Only the first three parameters are passed to the routine.  These are the
  2123. Handle of the file that you wish to send (use FOpen to get the handle) and
  2124. the Protocol$ that you wish to use ("Xmodem" or "Xmodem-1K"), and the current
  2125. Baud$.  On return, you will get an ErrCode if the other computer did not
  2126. respond, or MaxRec (the number of blocks to be sent), Record (the current
  2127. block number), and EstTime$ (an estimate of the time required to complete the
  2128. transfer.  The Protocol$ will have "CHK" or "CRC" added to it to indicate
  2129. whether checksum or CRC error detection is being used, depending on which the
  2130. receiver requested.
  2131.  
  2132. The secondary routine looks like this:
  2133.  
  2134.    XmodemSend Handle, Protocol$, MaxRec, Record, ErrCount, ErrCode
  2135.  
  2136. The ErrCode may be zero (no error), greater than zero (error reading file),
  2137. or less than zero (file transfer error, completion or abort).  See the
  2138. appendix on Error Codes for specific details.  The TERM.BAS example program
  2139. shows how these routines work together in practice.
  2140.  
  2141. The file accessed by the Xmodem routine will remain open.  Remember to close
  2142. it when the transfer is done (for whatever reason), using the FClose routine.
  2143.  
  2144.                               Telecommunications                       page 47
  2145.  
  2146.  
  2147.  
  2148. A few notes on the ins and outs of telecommunications...
  2149.  
  2150. The DTR signal is frequently used to control the modem.  When the DTR is
  2151. "raised" or "high", the modem knows that we're ready to do something.  When
  2152. the DTR is "dropped" or "low", the modem knows that we're not going to do
  2153. anything.  In most cases, this tells it to hang up or disconnect the phone
  2154. line.  Some modems may be set to ignore the DTR, in which case it will not
  2155. disconnect when the DTR is dropped.  Usually this can be fixed by changing a
  2156. switch on the modem.  On some modems, a short software command may suffice.
  2157.  
  2158. The DTR is generally the best way to disconnect.  The Hayes "ATH" command is
  2159. supposed to hang up, but it doesn't work very well.
  2160.  
  2161. The BasWiz comm handler makes sure the DTR is raised when TCInit is used.  It
  2162. does not automatically drop the DTR when TCDone is used, so you can keep the
  2163. line connected in case another program wants to use it.  If this is not
  2164. suitable, just use TCDTR to drop the DTR.  Your program must always use
  2165. TCDone before it exits, but it need only drop the DTR if you want it that
  2166. way.
  2167.  
  2168. If you want to execute another program via SHELL, it is ok to leave
  2169. communications running as long as control will return to your program when
  2170. the SHELLed program is done.  In that case, the input buffer will continue to
  2171. receive characters from the comm port unless the SHELLed program provides
  2172. its own comm support.  The output buffer will likewise continue to transmit
  2173. characters unless overruled.
  2174.  
  2175. An assortment of file transfer protocols will be provided in future versions
  2176. of BasWiz.  Among the ones supported will be Xmodem, Xmodem-1K, Ymodem
  2177. (batch), and Modem7 (batch).  I do not expect to support Kermit or Zmodem,
  2178. since they are unduly complicated.  You can handle any file transfer protocol
  2179. you like by SHELLing to an external protocol program, or of course you can
  2180. write your own support code.
  2181.  
  2182.                          The Virtual Windowing System                  page 48
  2183.  
  2184.  
  2185.  
  2186. The virtual windowing system offers pop-up and collapsing windows, yes... but
  2187. that is just a small fraction of what it provides.  When you create a window,
  2188. the part that you see on the screen may be only a view port on a much larger
  2189. window, called a virtual screen.  You can make virtual screens of up to 255
  2190. rows long or 255 columns wide.  The only limitation is that any single
  2191. virtual screen must take up less than 65,520 bytes.  Each virtual screen is
  2192. treated much like the normal screen display, with simple replacements for the
  2193. standard PRINT, LOCATE, and COLOR commands.  Many other commands are provided
  2194. for additional flexibility.  The window on the virtual screen may be moved,
  2195. resized, or requested to display a different portion of the virtual screen.
  2196. If you like, you may choose to display a frame and/or title around a window.
  2197. When you open a new window, any windows under it are still there and can
  2198. still be updated-- nothing is ever destroyed unless you want it that way!
  2199. With the virtual windowing system, you get a tremendous amount of control for
  2200. a very little bit of work.
  2201.  
  2202. The current version of the virtual windowing system only allows text mode
  2203. screens to be used.  All standard text modes are supported, however.  This
  2204. includes 25x40 CGA screens, the standard 25x80 screen, and longer screens
  2205. such as the 43x80 EGA screen.  The virtual windowing system is designed for
  2206. computers that offer hardware-level compatibility with the IBM PC, which
  2207. includes almost all MS-DOS/PC-DOS computers in use today.
  2208.  
  2209.  
  2210.  
  2211. Terminology:
  2212. -----------
  2213.  
  2214. DISPLAY
  2215.    The actual screen.
  2216.  
  2217. SHADOW SCREEN
  2218.    This is a screen kept in memory which reflects any changes you make to
  2219.    windows.  Rather than making changes directly on the actual screen, the
  2220.    virtual windowing system works with a "shadow screen" for increased speed
  2221.    and flexibility.  You specify when to update the display from the shadow
  2222.    screen.  This makes any changes appear very smoothly.
  2223.  
  2224. VIRTUAL SCREEN
  2225.    This is a screen kept in memory which can be treated much like the actual
  2226.    screen.  You may choose to make a virtual screen any reasonable size.
  2227.    Every virtual screen will have a corresponding window.
  2228.  
  2229. WINDOW
  2230.    This is the part of a virtual screen which is actually displayed.  You
  2231.    might think of a window as a "view port" on a virtual screen.  A window
  2232.    may be smaller than its virtual screen or the same size.  It may have a
  2233.    frame or a title and can be moved or resized.
  2234.  
  2235.                          The Virtual Windowing System                  page 49
  2236.  
  2237.  
  2238.  
  2239. Frankly, the virtual windowing system is one of those things that's more
  2240. difficult to explain than to use.  It's very easy to use, as a matter of
  2241. fact, but the basic concepts will need a little explanation.  Rather than
  2242. launching into a tedious and long-winded description of the system, I'm
  2243. going to take a more tutorial approach, giving examples and explaining as I
  2244. go along.  Take a look at the WDEMO.BAS program for additional insights.
  2245.  
  2246. Let's begin with the simplest possible scenario, where only a background
  2247. window is created.  This looks just like a normal screen.
  2248.  
  2249.    REM $INCLUDE: 'BASWIZ.BI'
  2250.    DEFINT A-Z
  2251.    Rows = 25: Columns = 80                         ' define display size
  2252.    WInit Rows, Columns, ErrCode                    ' initialize window system
  2253.    IF ErrCode THEN                                 ' stop if we couldn't...
  2254.       PRINT "Insufficient memory"
  2255.       END
  2256.    END IF
  2257.    Handle = 0                                      ' use background handle
  2258.    WWriteLn Handle, "This is going to be displayed on the background window."
  2259.    WWriteLn Handle, "Right now, that's the full screen."
  2260.    WUpdate                                         ' update the display
  2261.    WDone                                           ' terminate window system
  2262.  
  2263. What we just did was to display two lines on the screen-- nothing at all
  2264. fancy, but it gives you the general idea of how things work.  Let's take a
  2265. closer look at what the program does:
  2266.  
  2267.   - We INCLUDE the BASWIZ.BI definition file to let QuickBASIC know that
  2268.     we'll be using the BasWiz routines.
  2269.  
  2270.   - We define the size of the display using the integer variables Rows and
  2271.     Columns (you can use any variable names you want).  If you have an EGA
  2272.     display and had previously used WIDTH ,43 to go into 43x80 mode, you'd
  2273.     use "Rows = 43" here, for example.
  2274.  
  2275.   - We initialize the windowing system with WInit, telling it how large the
  2276.     display is.  It returns an error code if it is unable to initialize.
  2277.  
  2278.   - We define the Handle of the window that we want to use.  The "background
  2279.     window" is always available as handle zero, so we choose "Handle = 0".
  2280.  
  2281.   - We print two strings to the background window with WWriteLn, which is
  2282.     like a PRINT without a semicolon on the end (it moves to the next line).
  2283.  
  2284.   - At this point, only the shadow screen has been updated.  We're ready to
  2285.     display the information, so we use WUpdate to update the actual screen.
  2286.  
  2287.   - We're all done with the program, so we finish up with WDone.
  2288.  
  2289.                          The Virtual Windowing System                  page 50
  2290.  
  2291.  
  2292.  
  2293. See, there's nothing to it!  We initialize the screen, print to it or
  2294. whatever else we need to do, tell the windowing system to update the display,
  2295. and when the program is done, we close up shop.
  2296.  
  2297. The background screen is always available.  It might help to think of it as a
  2298. virtual screen that's the size of the display.  The window on this virtual
  2299. screen is exactly the same size, so the entire virtual screen is displayed.
  2300. As with other virtual screens, you can print to it without disturbing
  2301. anything else.  That means you can treat the background screen the same way
  2302. regardless of whether it has other windows on top of it-- the other windows
  2303. just "cover" the background information, which will still be there.
  2304.  
  2305. This leads us to the topic of creating windows.  Both a virtual screen and a
  2306. window are created simultaneously-- remember, a window is just a view port on
  2307. a virtual screen.  The window can be the same size as the virtual screen, in
  2308. which case the entire virtual screen is visible (as with the background
  2309. window) or it can be smaller than the virtual screen, in which case just a
  2310. portion of the virtual screen will be visible at any one time.
  2311.  
  2312. A window is created like so:
  2313.  
  2314.    ' This is a partial program and can be inserted in the original example
  2315.    ' after the second WWriteLn statement...
  2316.    VRows = 43: VColumns = 80                       ' define virtual screen size
  2317.    WOpen VRows, VColumns, 1, 1, Rows, Columns, Handle, ErrCode ' create window
  2318.    IF ErrCode THEN                                 ' error if we couldn't...
  2319.       PRINT "Insufficient memory available"
  2320.       WDone                                        ' (or use an error handler)
  2321.       END
  2322.    END IF
  2323.  
  2324. What we have done here is to create a virtual screen of 43 rows by 80
  2325. columns.  The window will be the size of the display, so if you are in the
  2326. normal 25x80 mode, only the first 25 rows of the virtual screen will be
  2327. visible.  If you have an EGA or VGA in 43x80 mode, though, the entire virtual
  2328. screen will be visible!  So, this window lets you treat a screen the same way
  2329. regardless of the display size.
  2330.  
  2331. The Handle returned is used any time you want to print to this new window or
  2332. otherwise deal with it.  If you are using many windows, you might want to
  2333. keep an array of handles, to make it easier to keep track of which is which.
  2334.  
  2335. By default, a virtual screen is created with the following attributes:
  2336.  
  2337.   - The cursor is at (1,1), the upper left corner of the virtual screen.
  2338.   - The cursor size is 0 (invisible).
  2339.   - The text color is 7,0 (white foreground on a black background).
  2340.   - There is no title or frame.
  2341.   - The window starts at (1,1) in the virtual screen, which displays the
  2342.     area starting at the upper left corner of the virtual screen.
  2343.  
  2344.                          The Virtual Windowing System                  page 51
  2345.  
  2346.  
  2347.  
  2348. When you create a new window, it becomes the "top" window, and will be
  2349. displayed on top of any other windows that are in the same part of the
  2350. screen.  Remember, you can print to a window or otherwise deal with it, even
  2351. if it's only partially visible or entirely covered by other windows.
  2352.  
  2353. Don't forget WUpdate!  None of your changes are actually displayed until
  2354. WUpdate is used.  You can make as many changes as you like before calling
  2355. WUpdate, which will display the results smoothly and at lightning speed.
  2356.  
  2357. We've created a window which is exactly the size of the display, but which
  2358. might well be smaller than its virtual screen.  Let's assume that the normal
  2359. 25x80 display is being used, in which case our virtual screen (43x80) is
  2360. larger than the window.  We can still print to the virtual screen normally,
  2361. but if we print below line 25, the results won't be displayed.  What a
  2362. predicament!  How do we fix this?
  2363.  
  2364. The window is allowed to start at any given location in the virtual screen,
  2365. so if we want to see a different portion of the virtual screen, all we have
  2366. to do is tell the window to start somewhere else.  When the window is
  2367. created, it starts at the beginning of the virtual screen, coordinate (1,1).
  2368. The WView routine allows us to change this.
  2369.  
  2370. In our example, we're displaying a 43x80 virtual screen in a 25x80 window.
  2371. To begin with, then, rows 1-25 of the virtual screen are visible.  To make
  2372. rows 2-26 of the virtual screen visible, we simply do this:
  2373.  
  2374.    WView Handle, 2, 1
  2375.  
  2376. That tells the window to start at row 2, column 1 in the virtual screen.
  2377. Sounds easy enough, doesn't it?  Well, if not, don't despair.  Play with it
  2378. in the QuickBASIC environment a little until you get the hang of it.
  2379.  
  2380. You've noticed that the window doesn't need to be the same size as the
  2381. virtual screen.  Suppose we don't want it the same size as the display,
  2382. either... suppose we want it in a nice box, sitting out of the way in a
  2383. corner of the display?  Well, we could have created it that way to begin with
  2384. when we used WOpen.  Since we've already created it, though, let's take a
  2385. look at the routines to change the size of a window and to move it elsewhere.
  2386. The window can be made as small as 1x1 or as large as its virtual screen, and
  2387. it can be moved anywhere on the display you want it.
  2388.  
  2389. Let's make the window a convenient 10 rows by 20 columns:
  2390.  
  2391.    WSize Handle, 10, 20
  2392.  
  2393. And move it into the lower right corner of the display:
  2394.  
  2395.    WPlace Handle, 12, 55
  2396.  
  2397.                          The Virtual Windowing System                  page 52
  2398.  
  2399.  
  2400.  
  2401. Don't forget to call WUpdate or the changes won't be visible!  Note also that
  2402. we didn't really lose any text.  The virtual screen, which holds all the
  2403. text, is still there.  We've just changed the size and position of the
  2404. window, which is the part of the virtual screen that we see, so less of the
  2405. text (if there is any!) is visible.  If we made the window larger again, the
  2406. text in the window would expand accordingly.
  2407.  
  2408. If you were paying close attention, you noticed that we didn't place the
  2409. resized window flush against the corner of the display.  We left a little bit
  2410. of room so we can add a frame and a title.  Let's proceed to do just that.
  2411.  
  2412. Window frames are displayed around the outside of a window and will not be
  2413. displayed unless there is room to do so.  We have four different types of
  2414. standard frames available:
  2415.  
  2416.    0   (no frame)
  2417.    1   single lines
  2418.    2   double lines
  2419.    3   single horizontal lines, double vertical lines
  2420.    4   single vertical lines, double horizontal lines
  2421.  
  2422. We must also choose the colors for the frame.  It usually looks best if the
  2423. background color is the same background color as used by the virtual screen.
  2424. Let's go ahead and create a double-line frame in bright white on black:
  2425.  
  2426.    FType = 2: Fore = 15: Back = 0
  2427.    WFrame Handle, FType, Fore, Back
  2428.  
  2429. If you'd rather not use the default frame types, there's ample room to get
  2430. creative!  Frames 5-9 can be defined any way you please.  They are null by
  2431. default.  To create a new frame type, you must specify the eight characters
  2432. needed to make the frame: upper left corner, upper middle columns, upper
  2433. right corner, left middle rows, right middle rows, lower left corner, lower
  2434. middle columns, and lower right corner.
  2435.  
  2436.    +----------------------------------------+
  2437.    |  Want a plain text frame like this?    |
  2438.    |  Use the definition string "+-+||+-+"  |
  2439.    +----------------------------------------+
  2440.  
  2441. The above window frame would be defined something like this:
  2442.  
  2443.    Frame = 5
  2444.    FrameInfo$ = "+-+||+-+"
  2445.    WUserFrame Frame, FrameInfo$
  2446.  
  2447. Of course, you can choose any values you like.  As always, the names of the
  2448. variables can be anything, as long as you name them consistently within your
  2449. program.  You can even use constants if you prefer:
  2450.  
  2451.    WUserFrame 5, "+-+||+-+"
  2452.  
  2453.                          The Virtual Windowing System                  page 53
  2454.  
  2455.  
  2456.  
  2457. If you use a frame, you can also have a "shadow", which provides a sort of
  2458. 3-D effect.  The shadow can be made up of any character you choose, or it can
  2459. be entirely transparent, in which case anything under the shadow will change
  2460. to the shadow colors.  This latter effect can be quite nice.  I've found that
  2461. it works best for me when I use a dim foreground color with a black
  2462. background-- a foreground color of 8 produces wonderful effects on machines
  2463. that support it (it's "bright black", or dark gray; some displays will show
  2464. it as entirely black, though, so it may not always work the way you want).
  2465. For a transparent shadow, select CHR$(255) as the shadow character.  You can
  2466. turn the shadow off with either a null string or CHR$(0).
  2467.  
  2468.    Shadow$ = CHR$(255)                     ' transparent shadow
  2469.    Fore = 8: Back = 0                      ' dark gray on black
  2470.    WShadow Handle, Shadow$, Fore, Back
  2471.  
  2472. A shadow will only appear if there is also a frame, and if there is enough
  2473. space for it on the screen.  Currently, there is only one type of shadow,
  2474. which appears on the right and bottom sides of the frame.  It effectively
  2475. makes the frame wider and longer by one character.
  2476.  
  2477. We can have a title regardless of whether a frame is present or not.  Like
  2478. the frame, the title is displayed only if there is enough room for it.  If
  2479. the window is too small to accommodate the full title, only the part of the
  2480. title that fits will be displayed.  The maximum length of a title is 70
  2481. characters.  Titles have their own colors.
  2482.  
  2483.    Title$ = "Wonderful Window!"
  2484.    Fore = 0: Back = 7
  2485.    WTitle Handle, Title$, Fore, Back
  2486.  
  2487. To get rid of a title, just use a null title string (Title$ = "").
  2488.  
  2489. It may be convenient to set up a window that isn't always visible-- say, for
  2490. a help window, perhaps.  The window could be set up in advance, then shown
  2491. whenever requested using just one statement:
  2492.  
  2493.    WHide Handle, Hide
  2494.  
  2495. You can make a window invisible by using any nonzero value for Hide, or make
  2496. it reappear by setting Hide to zero.  As always, the change will only take
  2497. effect after WUpdate is used.
  2498.  
  2499.                          The Virtual Windowing System                  page 54
  2500.  
  2501.  
  2502.  
  2503. When WWrite or WWriteLn gets to the end of a virtual screen, they normally
  2504. scroll the "screen" up to make room for more text.  This is usually what you
  2505. want, of course, but there are occasions when it can be a nuisance.  The
  2506. automatic scrolling can be turned off or restored like so:
  2507.  
  2508.    WScroll Handle, AutoScroll
  2509.  
  2510. There are only a few more ways of dealing with windows themselves.  After
  2511. that, I'll explain the different things you can do with text in windows and
  2512. how to get information about a specific window or virtual screen.
  2513.  
  2514. If you have a lot of windows, one window may be on top of another, obscuring
  2515. part or all of the window(s) below.  In order to make sure a window is
  2516. visible, all you need to do is to put it on top, right?  Hey, is this easy or
  2517. what?!
  2518.  
  2519.    WTop Handle
  2520.  
  2521. You may also need to "unhide" the window if you used WHide on it previously.
  2522.  
  2523. Note that the background window will always be the background window.  You
  2524. can't put handle zero, the background window, on top.  What?  You say you
  2525. need to do that?!  Well, that's one of the ways you can use the WCopy
  2526. routine.  WCopy copies one virtual screen to another one of the same size:
  2527.  
  2528.    WCopy FromHandle, ToHandle
  2529.  
  2530. You can copy the background window (or any other window) to another window.
  2531. The new window can be put on top, resized, moved, or otherwise spindled and
  2532. mutilated.  The WDEMO program uses this trick.
  2533.  
  2534. We've been through how to open windows, print to them, resize them and move
  2535. them around, among other things.  We've seen how to put a frame and a title
  2536. on a window and pop it onto the display.  If you're a fan of flashy displays,
  2537. though, you'd probably like to be able to make a window "explode" onto the
  2538. screen or "collapse" off.  It's the little details like that which make a
  2539. program visually exciting and professional-looking.  I wouldn't disappoint
  2540. you by leaving something fun like that out!
  2541.  
  2542. Since we're using a virtual windowing system rather than just a plain ol'
  2543. ordinary window handler, there's an extra benefit.  When a window explodes or
  2544. collapses, it does so complete with its title, frame, shadow, and even its
  2545. text.  This adds rather nicely to the effect.
  2546.  
  2547.                          The Virtual Windowing System                  page 55
  2548.  
  2549.  
  2550.  
  2551. To "explode" a window, we just set up all its parameters the way we normally
  2552. would-- open the window, add a title or frame if we like, print any text that
  2553. we want displayed, and set the screen position.  Then we use WExplode to zoom
  2554. the window from a tiny box up to its full size:
  2555.  
  2556.    WExplode Handle
  2557.  
  2558. The "collapse" routine works similarly.  It should be used only when you are
  2559. through with a window, because it closes the window when it's done.  The
  2560. window is collapsed from its full size down to a tiny box, then eliminated
  2561. entirely:
  2562.  
  2563.    WCollapse Handle
  2564.  
  2565. Note that WExplode and WCollapse automatically use WUpdate to update the
  2566. display.  You do not need to use WUpdate yourself and you should make sure
  2567. that the screen is the way you want it displayed before you call either
  2568. routine.
  2569.  
  2570. The WCollapse and WExplode routines were written in BASIC, so they'll be easy
  2571. to customize just the way you want them if you register BasWiz and get the
  2572. source code.  They're not particularly difficult routines, however, so you
  2573. might want to design a set of your own similar routines just for the
  2574. exercise.  All it takes is moving and resizing the windows.
  2575.  
  2576. The great thing about being a programmer is that you can do it your way.
  2577. Hold the pickles, hold the lettuce!  Might be fun to add some sound effects
  2578. to those exploding windows, hmmm?  I'll do that in a later version, but don't
  2579. feel obliged to wait for me!
  2580.  
  2581. That's it for the windows.  We've been through all the "tricky stuff".  There
  2582. are a number of useful things you can do with a virtual screen, though,
  2583. besides printing to it with WWriteLn.  Let's take a look at what we can do.
  2584.  
  2585. WWriteLn is fine if you want to use a "PRINT St$" sort of operation.  Suppose
  2586. you don't want to move to a new line afterward, though?  In BASIC, you'd use
  2587. something like "PRINT St$;" (with a semicolon).  With the virtual windowing
  2588. system, you use WWrite, which is called just like WWriteLn:
  2589.  
  2590.    WWrite Handle, St$
  2591.  
  2592. There are also routines that work like CLS, COLOR and LOCATE:
  2593.  
  2594.    WClear Handle
  2595.    WColor Handle, Fore, Back
  2596.    WLocate Handle, Row, Column
  2597.  
  2598. The WClear routine is not quite like CLS in that it does not affect the
  2599. cursor position.  If you want the cursor "homed", use WLocate.
  2600.  
  2601.                          The Virtual Windowing System                  page 56
  2602.  
  2603.  
  2604.  
  2605. Note that the coordinates for WLocate are based on the virtual screen, not
  2606. the window.  If you move the cursor to a location outside the view port
  2607. provided by the window, it will disappear.  Speaking of disappearing cursors,
  2608. you might have noticed that our WLocate doesn't mimic LOCATE exactly: it
  2609. doesn't provide for controlling the cursor size.  Don't panic!  There's
  2610. another routine available for that:
  2611.  
  2612.    WCursor Handle, CSize
  2613.  
  2614. The CSize value may range from zero (in which case the cursor will be
  2615. invisible) to the maximum size allowed by your display adapter.  This will
  2616. always be at least eight.
  2617.  
  2618. Now, since each virtual screen is treated much like the full display, you may
  2619. be wondering what happens if the cursor is "on" in more than one window.
  2620. Does that mean multiple cursors are displayed?  Well, no.  That would get a
  2621. little confusing!  Only the cursor for the top window is displayed.  If you
  2622. put a different window on top, the cursor for that window will be activated
  2623. and the cursor for the old top window will disappear.  The virtual windowing
  2624. system remembers the cursor information for each window, but it only actually
  2625. displays the cursor for the window that's on top.
  2626.  
  2627. In addition to the usual screen handling, the windowing system provides four
  2628. new capabilities which you may find very handy.  These are routines to insert
  2629. and delete both characters and rows.  This is done at the current cursor
  2630. position within a selected virtual screen:
  2631.  
  2632.    WDelChr Handle
  2633.    WDelLine Handle
  2634.    WInsChr Handle
  2635.    WInsLine Handle
  2636.  
  2637. These routines can also be used for scrolling.  Remember, the display isn't
  2638. updated until you use WUpdate, and then it's updated all at once.  You can
  2639. use any of the routines multiple times and the display will still be updated
  2640. perfectly smoothly-- all the real work goes on behind the scenes!
  2641.  
  2642. When you are done with a virtual screen and no longer need it, you can
  2643. dispose of it like so:
  2644.  
  2645.    WClose Handle
  2646.  
  2647. All of the information that can be "set" can also be retrieved.  That's
  2648. useful in general, of course, but it's also a great feature for writing
  2649. portable subprograms.  You can create subprograms that will work with any
  2650. virtual screen, since it can retrieve any information it needs to know about
  2651. the virtual screen or its window.  That's power!
  2652.  
  2653.                          The Virtual Windowing System                  page 57
  2654.  
  2655.  
  2656.  
  2657. Here is a list of the available window data retrieval routines:
  2658.  
  2659.    WGetColor Handle, Fore, Back
  2660.    ' gets the current foreground and background colors
  2661.  
  2662.    WGetCursor Handle, CSize
  2663.    ' gets the cursor size
  2664.  
  2665.    WGetFrame Handle, Frame, Fore, Back
  2666.    ' gets the frame type and frame colors
  2667.  
  2668.    WGetLocate Handle, Row, Column
  2669.    ' gets the cursor position
  2670.  
  2671.    WGetPlace Handle, Row, Column
  2672.    ' gets the starting position of a window on the display
  2673.  
  2674.    WGetScroll Handle, AutoScroll
  2675.    ' gets the status of auto-scroll (scrolling at the end of a virtual screen)
  2676.  
  2677.    Shadow$ = SPACE$(1)
  2678.    WGetShadow Handle, Shadow$, Fore, Back
  2679.    ' gets the shadow character (CHR$(0) if there's no shadow) and colors
  2680.  
  2681.    WGetSize Handle, Rows, Columns
  2682.    ' gets the size of a window
  2683.  
  2684.    Title$ = SPACE$(70)
  2685.    WGetTitle Handle, Title$, TLen, Fore, Back
  2686.    Title$ = LEFT$(Title$, TLen)
  2687.    ' gets the title string (null if there's no title) and title colors
  2688.  
  2689.    WGetTop Handle
  2690.    ' gets the handle of the top window
  2691.  
  2692.    FrameInfo$ = SPACE$(8)
  2693.    WGetUFrame$ Frame, FrameInfo$
  2694.    ' gets the specification for a given user-defined frame type
  2695.  
  2696.    WGetView Handle, Row, Column
  2697.    ' gets the starting position of a window within a virtual screen
  2698.  
  2699.    WGetVSize Handle, Rows, Columns
  2700.    ' gets the size of a virtual screen
  2701.  
  2702.    WHidden Handle, Hidden
  2703.    ' tells you whether a window is visible
  2704.  
  2705.                          The Virtual Windowing System                  page 58
  2706.  
  2707.  
  2708.  
  2709. As well as displaying information in a window, you will frequently want to
  2710. allow for getting input from the user.  Of course, INKEY$ will still work
  2711. fine, but that's not an effective way of handling more than single
  2712. characters.  The virtual windowing system includes a flexible string input
  2713. routine which is a lot more powerful:
  2714.  
  2715.    WInput Handle, Valid$, ExitCode$, ExtExitCode$, MaxLength, St$, ExitKey$
  2716.  
  2717. The Valid$ variable allows you to specify a list of characters which may be
  2718. entered.  If you use a null string (""), any character will be accepted.
  2719.  
  2720. ExitCode$ specifies the normal keys that can be used to exit input.  You'll
  2721. probably want to use a carriage return, CHR$(13), for this most of the time.
  2722. You can also specify exit on extended key codes like arrow keys and function
  2723. keys via ExtExitCode$.
  2724.  
  2725. MaxLength is the maximum length of the string you want.  Use zero to get the
  2726. longest possible string.  The length may go up to the width of the virtual
  2727. screen, minus one character.  The window will be scrolled sideways as needed
  2728. to accommodate the full length of the string.
  2729.  
  2730. The St$ variable is used to return the entered string, but you can also use
  2731. it to pass a default string to the routine.
  2732.  
  2733. ExitKey$ returns the key that was used to exit input.
  2734.  
  2735. A fairly strong set of editing capabilities is available through WInput.
  2736. The editing keys can be overridden by ExitCode$ or ExtExitCode$, but by
  2737. default they include support for both the cursor keypad and WordStar:
  2738.  
  2739.    Control-S   LeftArrow    move left once
  2740.    Control-D   RightArrow   move right once
  2741.    Control-V   Ins          switch between insert and overstrike modes
  2742.    Control-G   Del          delete current character
  2743.    Control-H   Backspace    destructive backspace
  2744.                Home         move to the start of input
  2745.                End          move to the end of input
  2746.  
  2747.                          The Virtual Windowing System                  page 59
  2748.  
  2749.  
  2750.  
  2751. Pop-up menus have become very popular in recent years.  Fortunately, they are
  2752. a natural application for virtual windows!  BasWiz provides a pop-up menuing
  2753. routine which allows you to have as many as 255 choices-- the window will be
  2754. scrolled automatically to accommodate your "pick list", with a highlight bar
  2755. indicating the current selection.
  2756.  
  2757. The pop-up menu routine uses a window which you've already set up, so you can
  2758. use any of the normal window options-- frames, titles, shadows, etc.  You
  2759. must provide a virtual screen large enough to hold your entire pick list; the
  2760. window itself can be any size at all.
  2761.  
  2762. The pick list is passed to WMenuPopUp through a string array.  You can
  2763. dimension this array in any range that suits you.  The returned selection
  2764. will be the relative position in the array (1 for the first item, etc); if
  2765. the menu was aborted, 0 will be returned instead.
  2766.  
  2767. The current window colors will be used for the "normal" colors.  You specify
  2768. the desired highlight colors when calling the pop-up menu routine.
  2769.  
  2770.    Result = WMenuPopUp(Handle, PickList$(), HiFore, HiBack)
  2771.  
  2772. The mouse is not supported, since BasWiz does not yet have mouse routines.
  2773. However, scrolling can be accomplished with any of the more common methods:
  2774. up and down arrows, WordStar-type Control-E and Control-X, or Lotus-type tab
  2775. and backtab.  The ESCape key can be used to abort without choosing an option.
  2776.  
  2777. On exit, the menu window will remain in its final position, in case you wish
  2778. to pop up a related window next to it or something similar.  Since it's just
  2779. an ordinary window, you can use WClose or WCollapse if you prefer to get rid
  2780. of it.
  2781.  
  2782. The WMenuPopUp routine was written in BASIC, so you will find it easy to
  2783. modify to your tastes if you register BasWiz.  It was written with extra
  2784. emphasis on comments and clarity, since I know many people will want to
  2785. customize this routine!
  2786.  
  2787.                          The Virtual Windowing System                  page 60
  2788.  
  2789.  
  2790.  
  2791. There are two more routines which allow the virtual windowing system to work
  2792. on a wide variety of displays: WFixColor and WSnow.
  2793.  
  2794. Chances are, as a software developer you have a color display.  However,
  2795. there are many people out there who have monochrome displays, whether due to
  2796. preference, a low budget, or use of notebook-style computers with mono LCD or
  2797. plasma screens.  WFixColor allows you to develop your programs in color while
  2798. still supporting monochrome systems.  It tells the VWS whether to keep the
  2799. colors as specified or to translate them to their monochrome equivalents:
  2800.  
  2801.    WFixColor Convert%
  2802.  
  2803. Set Convert% to zero if you want true color (default), or to any other value
  2804. if you want the colors to be translated to monochrome.  In the latter case,
  2805. the translation will be done based on the relative brightness of the
  2806. foreground and background colors.  The result is guaranteed to be readable on
  2807. a monochrome system if it's readable on a color system.  You should check the
  2808. results on your system to make sure that such things as highlight bars still
  2809. appear highlighted, however.
  2810.  
  2811. In the case of some of the older or less carefully designed CGA cards, the
  2812. high-speed displays of the virtual windowing system can cause the display to
  2813. flicker annoyingly.  You can get rid of the flicker at the expense of slowing
  2814. the display:
  2815.  
  2816.    WSnow Remove%
  2817.  
  2818. Set Remove% to zero if there is no problem with "snow" or flickering
  2819. (default), or to any other value if you need "snow removal".  Using snow
  2820. removal will slow down the display substantially, which may be a problem if
  2821. you update (WUpdate) it frequently.
  2822.  
  2823. Note that you can't detect either of these cases automatically with perfect
  2824. reliability.  Not all CGA cards have flicker problems.  Monochrome displays
  2825. may be attached to CGA cards and the computer won't know the difference.  A
  2826. VGA with a paper-white monitor may well think it has color, and will mostly
  2827. act like it, but some "color" combinations can be very difficult to read.
  2828. While you can self-configure the program to some extent using the GetDisplay
  2829. routine (see Other Routines), you should also provide command-line switches
  2830. so that the user can override your settings.  Microsoft generally uses "/B"
  2831. to denote a monochrome ("black and white") display, so you may want to follow
  2832. that as a standard.  I would suggest "/F" to turn on CGA flicker suppression.
  2833.  
  2834. And that, folks, is all there is to it.  See WDEMO.BAS and TERM.BAS for
  2835. working examples.  Also see "Telecommunications" for information about a
  2836. routine which handles ANSI display and music codes; it displays to the window
  2837. of your choice.
  2838.  
  2839.                                 Other Routines                         page 61
  2840.  
  2841.  
  2842.  
  2843. There are a number of routines for which I couldn't find a specific category.
  2844.  
  2845. To see how much expanded memory is available, use the GetEMS function.  It'll
  2846. return zero if there is no expanded memory installed:
  2847.  
  2848.    PRINT "Kbytes of expanded memory:"; GetEMS
  2849.  
  2850. The GetDisplay routine tells what kind of display adapter is active and
  2851. whether it's hooked up to a color monitor.  The only time it can't detect the
  2852. monitor type is on CGA setups (it assumes "color").  It's a good idea to
  2853. allow a "/B" switch for your program so the user can specify if a monochrome
  2854. monitor is attached to a CGA.
  2855.  
  2856.    GetDisplay Adapter, Mono
  2857.    IF Mono THEN
  2858.       PRINT "Monochrome monitor"
  2859.    ELSE
  2860.       PRINT "Color monitor"
  2861.    END IF
  2862.    SELECT CASE Adapter
  2863.       CASE 1: PRINT "MDA"
  2864.       CASE 2: PRINT "Hercules"
  2865.       CASE 3: PRINT "CGA"
  2866.       CASE 4: PRINT "EGA"
  2867.       CASE 5: PRINT "MCGA"
  2868.       CASE 6: PRINT "VGA"
  2869.    END SELECT
  2870.  
  2871. The ScreenSize routine returns the number of rows and columns on the display
  2872. (text modes only):
  2873.  
  2874.    ScreenSize Rows%, Columns%
  2875.  
  2876.                              Miscellaneous Notes                       page 62
  2877.  
  2878.  
  2879.  
  2880. The virtual windowing system allows up to 16 windows to be open at a time,
  2881. including the background window, which is opened automatically.  This is
  2882. subject to available memory, of course.
  2883.  
  2884. The far string handler allows up to 65,535 strings of up to 255 characters
  2885. each, subject to available memory.  When the handler needs additional memory
  2886. for string storage, it allocates more in blocks of 16 Kbytes.  If that much
  2887. memory is not available, an "out of memory" error will be generated (BASIC
  2888. error number 7).  You can check the size of the available memory pool using
  2889. the SETMEM function provided by QuickBASIC.
  2890.  
  2891. The communications handler only allows one comm port to be used at a time.
  2892. This will change in a future version of BasWiz.
  2893.  
  2894. The file handler does not allow you to combine Write mode with Text mode or
  2895. input buffering.  This will change in a future version of BasWiz.
  2896.  
  2897. A certain lack of speed is inherent in BCD math, especially if you require
  2898. high precision.  The division, root, and trig routines in particular are
  2899. quite slow.  I'll attempt to improve this in the future, but the routines are
  2900. already fairly well optimized, so don't expect miracles.  Precision costs!
  2901.  
  2902. The fraction routines are much faster, but they have a much smaller range.
  2903. I'll have to do some experimenting on that.  It may prove practical to use a
  2904. subset of the BCD routines to provide an extended range for fractions without
  2905. an unreasonable loss in speed.
  2906.  
  2907. All routines are designed to be as bomb-proof as possible.  If you pass an
  2908. invalid value to a routine which does not return an error code, it will
  2909. simply ignore the value.
  2910.  
  2911. It's always possible that a problem has escaped notice.  If you run into
  2912. something that you believe to be a bug or incompatibility, please tell me
  2913. about it, whether you've registered BasWiz or not.
  2914.  
  2915. Do you like what you see?  Tell me what you like, what you don't like, and
  2916. what you'd be interested in seeing in future versions!  Chances are good that
  2917. I'll use your suggestions.  If you know of a good reference book or text
  2918. file, I'd like to hear about that too!  You can reach me through U.S. Mail or
  2919. through several of the international BASIC conferences on BBSes.
  2920.  
  2921.                              Miscellaneous Notes                       page 63
  2922.  
  2923.  
  2924.  
  2925. The EGA graphics routines are designed for use with EGAs having at least 256K
  2926. RAM on board.  They will not operate properly on old 64K EGA systems.
  2927.  
  2928. Image loading (.MAC and .PCX) is quite slow.  The bulk of the code is in
  2929. BASIC at this point, to make it easier for me to extend the routines to cover
  2930. other graphics modes.  They will be translated to assembly later.
  2931.  
  2932. The G#Write and G#WriteLn services support three different fonts: 8x8, 8x14,
  2933. and 8x16.  The default font is always 8x8, providing the highest possible
  2934. text density.  QuickBASIC, on the other hand, allows only one font with a
  2935. text density of as close to 80x25 as possible.
  2936.  
  2937. The G#Write and G#WriteLn services interpret ASCII control characters, i.e.
  2938. CHR$(0) - CHR$(31), according to the more standard handling used by DOS
  2939. rather than the esoteric interpretation offered by QuickBASIC.  This is not
  2940. exactly a limitation, but it could conceivably cause confusion if your
  2941. program happens to use these characters.  The ASCII interpretation works as
  2942. follows:
  2943.  
  2944.     Code       Meaning
  2945.     ====       =======
  2946.       7        Bell      (sound a beep through the speaker)
  2947.       8        Backspace (destructive: eliminates the previous character)
  2948.       9        Tab       (based on 8-character tab fields)
  2949.      10        LineFeed  (move down one line, keep current column)
  2950.      12        FormFeed  (clear the screen)
  2951.      13        Return    (move to the start of the current line)
  2952.  
  2953. G#MirrorH will only work properly on images with byte alignment!  This means
  2954. that the width of the image must be evenly divisible by four if SCREEN 1 is
  2955. used, or evenly divisible by eight if SCREEN 2 is used.
  2956.  
  2957. The graphics routines provide little error checking and will not do clipping
  2958. (which ignores points outside the range of the graphics mode). If you specify
  2959. coordinates which don't exist, the results will be unusual at best.  Try to
  2960. keep those values within the proper range!
  2961.  
  2962. A very few of the graphics routines are slower than their counterparts in
  2963. QuickBASIC.  These are mostly drawing diagonal lines and filling boxes.  I
  2964. hope to get these better optimized in a future release.  The GET/PUT image
  2965. replacements are quite slow, but that's strictly temporary!  I rushed 'em in
  2966. by special request from a registered BasWiz owner.
  2967.  
  2968.                              Miscellaneous Notes                       page 64
  2969.  
  2970.  
  2971.  
  2972. If you use PRINT in conjunction with GN4Write or GN4WriteLn, be sure to save
  2973. the cursor position before the PRINT and restore it afterwards.  BASIC and
  2974. BasWiz share the same cursor position, but each interprets it to mean
  2975. something different.
  2976.  
  2977. The GN0 (360x480x256) and GN1 (320x400x256) routines use nonstandard VGA
  2978. modes.  The GN1 routines should work on just about any VGA, however.  The GN0
  2979. routines will work on many VGAs, but are somewhat less likely to work than
  2980. the GN1 routines due to the techniques involved.
  2981.  
  2982. The GN0Write, GN0WriteLn, GN1Write and GN1WriteLn routines are somewhat slow
  2983. in general and quite slow when it comes to scrolling the screen. These
  2984. problems are related to peculiarities of these modes that I'm still grappling
  2985. with.  They will hopefully be improved in a future release.
  2986.  
  2987. The G1Border routine is normally used to select the background (and border)
  2988. color for SCREEN 1 mode.  It can also be used in SCREEN 2 mode, where it will
  2989. change the foreground color instead.  Note that this may produce peculiar
  2990. results if an EGA or VGA is used and it isn't locked into "CGA" mode, so be
  2991. careful if your program may run on systems with displays other than true CGAs.
  2992.  
  2993. GET/PUT images have a lot of possibilities that Microsoft has never touched
  2994. on.  I'll be exploring this extensively in future versions.  Among other
  2995. things, expect the ability to change the colors, rotate the image, and
  2996. translate the image from one graphics mode format to another.  Enlarging and
  2997. shrinking the image will also be a good bet.
  2998.  
  2999. Note that you can GET an image in SCREEN 1 and PUT it in SCREEN 2!  It'll be
  3000. shaded instead of in colors.  This is a side-effect of the CGA display format.
  3001.  
  3002. The first two elements of a GET/PUT array (assuming it's an integer array)
  3003. tells you the size of the image.  The first element is the width and the
  3004. second is the height, in pixels.  Actually, that's not quite true.  Divide
  3005. the first element by 2 for the width if the image is for SCREEN 1, or by 8 if
  3006. for SCREEN 13.
  3007.  
  3008.                                   Error Codes                          page 65
  3009.  
  3010.  
  3011.  
  3012. The expression evaluator returns the following error codes:
  3013.  
  3014.    0    No error, everything went fine
  3015.    2    A number was expected but not found
  3016.    4    Unbalanced parentheses
  3017.    8    The expression string had a length of zero
  3018.    9    The expression included an attempt to divide by zero
  3019.  
  3020.  
  3021.  
  3022. The far string handler does not return error codes.  If an invalid string
  3023. handle is specified for FSSet, it will be ignored; if for FSGet, a null
  3024. string will be returned.  If you run out of memory for far strings, an "out
  3025. of memory" error will be generated (BASIC error #7).  You can prevent this by
  3026. checking available memory beforehand with the SETMEM function provided by
  3027. QuickBASIC.  Far string space is allocated as needed in blocks of just over
  3028. 16 Kbytes, or 16,400 bytes to be exact.
  3029.  
  3030.  
  3031.  
  3032. The telecommunications handler returns the following error codes for TCInit:
  3033.  
  3034.    0    No error, everything A-Ok
  3035.    1    The comm handler is already installed (you tried to install it twice)
  3036.    2    Invalid comm port specified
  3037.    3    Not enough memory available for input and output buffers
  3038.  
  3039.  
  3040.  
  3041. The telecommunications handler returns these error codes for Xmodem Send:
  3042.  
  3043.  -13    FATAL   : Abort due to selection of an unsupported transfer protocol
  3044.  -12    FATAL   : Abort due to excessive errors
  3045.  -11    FATAL   : Abort (by keyboard <ESC> or receiver CANcel request)
  3046.   -5    WARNING : Checksum or CRC error
  3047.   -1    WARNING : Time-out error (the receiver didn't respond)
  3048.    0    DONE    : No error, transfer completed ok
  3049.   >0    ERROR   : Problem reading from the file (see file error codes)
  3050.  
  3051.                                  Error Codes                           page 66
  3052.  
  3053.  
  3054.  
  3055. The file services return the following error codes:
  3056. (The asterisk "*" is used to identify so-called "critical errors")
  3057.  
  3058.    0    No error
  3059.    1    Invalid function number (usually means "invalid parameter(s)")
  3060.    2    File not found
  3061.    3    Path not found
  3062.    4    Too many open files
  3063.    5    Access denied (probably "write to read-only file")
  3064.    6    Invalid file handle
  3065.    7    Memory control blocks destroyed
  3066.    8    Insufficient memory (usually RAM, sometimes disk)
  3067.    9    Incorrect memory pointer specified
  3068.   15    Invalid drive specified
  3069. * 19    Tried to write on a write-protected disk
  3070. * 21    Drive not ready
  3071. * 23    Disk data error
  3072. * 25    Disk seek error
  3073. * 26    Unknown media type
  3074. * 27    Sector not found
  3075. * 28    Printer out of paper
  3076. * 29    Write fault
  3077. * 30    Read fault
  3078. * 31    General failure
  3079. * 32    Sharing violation
  3080. * 33    Lock violation
  3081. * 34    Invalid disk change
  3082.   36    Sharing buffer overflow
  3083.  
  3084.  
  3085.  
  3086. A "critical error" is one that would normally give you the dreaded prompt:
  3087.  
  3088.    A>bort, R>etry, I>gnore, F>ail?
  3089.  
  3090. Such errors generally require some action on the part of the user.  For
  3091. instance, they may need to close a floppy drive door or replace the paper in
  3092. a printer.  If a critical error occurs on a hard drive, it may indicate a
  3093. problem in the drive hardware or software setup.  In that case, the problem
  3094. may possibly be cleared up by "CHKDSK /F", which should be executed directly
  3095. from the DOS command line (do not execute this by SHELL).
  3096.  
  3097.                                Troubleshooting                         page 67
  3098.  
  3099.  
  3100.  
  3101. Problem:
  3102.    QB says "subprogram not defined".
  3103.  
  3104. Solution:
  3105.    The definition file was not included.  Your program must contain the line
  3106.       REM $INCLUDE: 'BASWIZ.BI'
  3107.    before any executable code in your program.  You should also start
  3108.    QuickBASIC with
  3109.       QB /L BASWIZ
  3110.    so it knows to use the BasWiz library.
  3111.  
  3112.  
  3113. Problem:
  3114.    LINK says "unresolved external reference".
  3115.  
  3116. Solution:
  3117.    Did you specify BasWiz as the library when you used LINK?  You should!
  3118.    The BASWIZ.LIB file must be in the current directory or along a path
  3119.    specified by the LIB environment variable (like PATH, but for LIB files).
  3120.  
  3121.  
  3122. Problem:
  3123.    The virtual windowing system doesn't display anything.
  3124.  
  3125. Solution:
  3126.    Perhaps you left out the WUpdate routine?  If so, the shadow screen is not
  3127.    reflected to the actual screen and nothing will appear.  The screen also
  3128.    needs to be in text mode (either no SCREEN statement or SCREEN 0).
  3129.    Finally, only the default "page zero" is supported on color monitors.
  3130.  
  3131.  
  3132. Problem:
  3133.    The virtual windowing system causes the display to flicker on CGAs.
  3134.  
  3135. Solution:
  3136.    Use the WSnow routine to get rid of it.  This will, unfortunately, slow
  3137.    the display down severely.  You might want to upgrade your display card!
  3138.  
  3139.  
  3140. Problem:
  3141.    QuickBASIC doesn't get along with the Hercules display routines.
  3142.  
  3143. Solution:
  3144.    Are you using an adapter which includes Hercules mode along with EGA or
  3145.    VGA mode?  QuickBASIC doesn't like that, since it thinks you'll be using
  3146.    EGA or VGA mode.  Use the stand-alone compiler (BC.EXE) instead of the
  3147.    environment (QB.EXE) and you should be fine.  You might also consider
  3148.    getting a separate Herc adapter and monochrome monitor.  It's possible to
  3149.    combine a Hercules monochrome adapter with a CGA, EGA or VGA.
  3150.  
  3151.                                Troubleshooting                         page 68
  3152.  
  3153.  
  3154.  
  3155. Problem:
  3156.    QB says "out of memory" (or "range out of bounds" on a DIM or REDIM).
  3157.  
  3158. Solution:
  3159.    If you're using the memory management/pointer routines, you've probably
  3160.    allocated too much memory!  You need to leave some for QuickBASIC.  Use
  3161.    the SETMEM function provided by BASIC to determine how much memory is
  3162.    available before allocating memory.  The amount needed by QuickBASIC will
  3163.    depend on your program.  The primary memory-eaters are arrays and
  3164.    recursive subprograms or functions.
  3165.  
  3166.    Many of the BasWiz routines need to allocate memory, including the virtual
  3167.    window manager, telecommunications handler, and memory management system.
  3168.    Besides checking with SETMEM to make sure there's memory to spare, don't
  3169.    forget to check the error codes returned by these routines to make sure
  3170.    they're working properly!
  3171.  
  3172.  
  3173. Problem:
  3174.    The cursor acts funny (appears when it shouldn't or vice versa).
  3175.  
  3176. Solution:
  3177.    Try locking your EGA or VGA into a specific video mode using the utility
  3178.    provided with your display adapter.  Cursor problems are usually related
  3179.    either to "auto mode detection" or older EGAs.
  3180.  
  3181.  
  3182. Problem:
  3183.    The BCD trig functions return weird results.
  3184.  
  3185. Solution:
  3186.    Make sure you've made room in your BCD size definition for some digits to
  3187.    the left of the decimal as well as to the right!  Calculations with large
  3188.    numbers are needed to return trig functions with high accuracy.
  3189.  
  3190.  
  3191. Problem:
  3192.    The G#MirrorH routine is -almost- working right, but the results are
  3193.    truncated or wrapped to one side.
  3194.  
  3195. Solution:
  3196.    Make your GET image a tad wider!  The number of pixels wide must be evenly
  3197.    divisible by four in SCREEN 1, or by eight in SCREEN 2.
  3198.  
  3199.                             History and Philosophy                     page 69
  3200.  
  3201.  
  3202.  
  3203. "History," you say.  "Philosophy.  What the heck does that have to do with a
  3204. BASIC library?  Yuck!  Go away and leave me alone!"
  3205.  
  3206. Ok.  This section is not strictly necessary for using BasWiz.  If you're not
  3207. interested, you can certainly avoid reading this without ill effects.  "Suit
  3208. yourself," he said with a bow and a flourish.
  3209.  
  3210. Still here?  Thank you!  I'll try to keep it short.
  3211.  
  3212. Back in 'bout 1984 or so, I created ADVBAS, one of the very first assembly
  3213. language libraries for BASIC.  That was for IBM BASCOM 1.0, well before
  3214. QuickBASIC came out.  I created the library for my own use and ended up
  3215. making a moderately successful shareware project out of it.
  3216.  
  3217. ADVBAS was designed in bits and pieces that came along whenever I felt like
  3218. adding to the library or needed a new capability.  The routines were designed
  3219. at a low level, with most of the actual work needed to accomplish anything
  3220. useful left to BASIC.  All this resulted in a decent amount of flexibility
  3221. but also a good deal of chaos as new routines provided capabilities that
  3222. overlapped with old routines.  Although I tried to keep the calling sequence
  3223. reasonably standardized, it didn't always work out that way.  Then too, the
  3224. library was designed well before the neat capabilities of QuickBASIC 4.0 came
  3225. into being and couldn't take good advantage of them.
  3226.  
  3227. Second came ProBas, a commercial version of ADVBAS.  ProBas was a vastly more
  3228. powerful superset of the ADVBAS library.  Unfortunately, it suffered from the
  3229. same flaws.  No old routines could be discarded or even modified if at all
  3230. possible, to provide compatibility from one version to the next.  The lack of
  3231. thought inherent in the original design caused a mad proliferation of
  3232. routines, many overlapping, most still low-level and hard to use.  At version
  3233. 5.0 (not yet released at the time I write this), there are over 800 different
  3234. routines-- something for everyone, to be sure, but tending towards complete
  3235. pandemonium.
  3236.  
  3237. The BasWiz project is a third-generation library.  It is designed to overcome
  3238. the liabilities I've encountered with ADVBAS and every other library I've
  3239. seen for BASIC.  Rather than being put together haphazardly, one routine at a
  3240. time, I have designed BasWiz as a coordinated collection.  The virtual
  3241. windowing system is an excellent example of this.  Rather than having
  3242. separate print routines, window routines, screen saving routines, virtual
  3243. screen routines and all the rest, it is all combined into one single
  3244. package.  The routines are designed at a high level, providing a maximum of
  3245. functionality with a minimum of programming effort.  The gritty details are
  3246. kept hidden inside the library where you need never deal with them.  Consider
  3247. the apparent simplicity of the far string handler!  Many more capabilities
  3248. will be added in future versions, but... very carefully.
  3249.  
  3250.                             History and Philosophy                     page 70
  3251.  
  3252.  
  3253.  
  3254. This library represents the culmination of many years of experience in the
  3255. fields of BASIC and assembly language programming.  I have spared no effort.
  3256. It's the best I can offer and I hope you'll forgive me for taking some pride
  3257. in my work!  If you find this library powerful and easy to use, I'll count my
  3258. efforts a great success.
  3259.  
  3260. As you might have guessed, I'm not exactly in it "just for the money."
  3261. Nonetheless, money is always nice!  If you like BasWiz, please do register.
  3262. That will enable me to continue to upgrade my equipment and reference library
  3263. so I can design more advanced BasWiz routines.
  3264.  
  3265.                             Using BasWiz with PDQ                      page 71
  3266.  
  3267.  
  3268.  
  3269. Most of the BasWiz routines will work with current versions of PDQ without
  3270. any modification.  The major exceptions are the expression evaluator, the BCD
  3271. and fraction math routines, and the polygon-generating graphics routines.
  3272. These should work fine once Crescent adds floating-point support to PDQ (I
  3273. understand this will be included in a new version to be released soon).
  3274.  
  3275. The .EXE files that come with the BasWiz library are LINKed with PDQ, which
  3276. is why they're so small.
  3277.  
  3278. Older versions of Crescent Software's PDQ library do not support the SETMEM
  3279. function, which is required by many BasWiz routines.  If your version of PDQ
  3280. is before v2.10, you must LINK in the SETMEM stub provided with BasWiz:
  3281.  
  3282.    LINK program+PDQSTUB/NOD,,NUL,BASWIZ+PDQ;
  3283.  
  3284. If you use LINK differently, that's fine.  The only thing necessary is to
  3285. make sure "+PDQSTUB" is listed after the name of your program as the first
  3286. LINK argument.  Use of /EX and other LINK parameters is no problem.  Use of
  3287. other libraries, if any, is also supported.  I've found that, for some
  3288. reason, PDQ usually wants to be the last library listed, by the way.
  3289.  
  3290. Crescent thoughtfully provided me with a free copy of PDQ in order that I
  3291. might resolve any incompatibilities between it and BasWiz.  If you are not
  3292. familiar with PDQ, it is a replacement library for BASIC's own runtime
  3293. libraries.  While not providing every capability of plain QuickBASIC, it
  3294. allows you to create substantially smaller EXE files for those programs that
  3295. qualify.  Support is currently lacking for floating point (single/double
  3296. precision) numbers, music, and graphics, among other things.  I understand
  3297. that these features will be available in future revisions.  Communications
  3298. support is available as an add-on package.    PDQ also adds new capabilities
  3299. which are quite impressive, such as being able to write small TSRs in BASIC.
  3300. Check with Crescent Software for more recent details.
  3301.  
  3302.                                   Credits                              page 72
  3303.  
  3304.  
  3305.  
  3306. For some of the reference works I have used in writing BasWiz, see the
  3307. BIBLIO.TXT file.
  3308.  
  3309. Special thanks to Howard Mencher (aka Dudeman Howie) for his thorough and
  3310. attentive beta-testing.
  3311.  
  3312. I am also indebted to the following people, among others:
  3313.  
  3314. Bill Cliver, president of F & I Controls (Arizona), which markets software
  3315. and hardware solutions for every aspect of car dealerships.
  3316.  
  3317. Mike Welch, co-sysop of The Shipyard BBS, the best BASIC support BBS that
  3318. I've ever encountered.  Among other fine acts, he is responsible for the
  3319. S&B4EGA and VGABOX demonstration programs which accompany BasWiz.  The
  3320. Shipyard is at 214-686-1962 (Texas)-- use the name "Quick Basic" and the
  3321. password "Quickshare" for instant access.
  3322.  
  3323. The inverse hyperbolic trig functions are based on a set of BASIC routines by
  3324. Kerry Mitchell.
  3325.  
  3326. The 360x480 256-color VGA mode was made possible by John Bridges' VGAKIT
  3327. library for C.  Two of the most vital low-level routines are based directly
  3328. on code from VGAKIT.  If you use C, check your local BBS for this library.
  3329. Last I looked, VGAKIT41.ZIP was the current version.
  3330.  
  3331. The 320x400 VGA mode was made possible by Michael Abrash's graphics articles
  3332. in Programmer's Journal.  His column alone is worth the subscription.
  3333.  
  3334. Definicon Corp very kindly released a public-domain program called SAMPLE.C
  3335. which shows how to access the 64k banks used by extended VGA 256-color modes.
  3336. This was the key to the GN5xxx routines (the so-called "tech ref" section of
  3337. my SuperVGA manual referred me to IBM's VGA docs, which would be utterly
  3338. useless in accessing these modes).  Since bank switching turns out to be
  3339. quite trivial, this is a rather pathetic lack in the BOCA Research, Inc.,
  3340. documentation (and hardly contributes to the use of SuperVGA modes).
  3341.  
  3342.